private List<URL> generateExecutionClasspath( Set<Artifact> resolvedArtifacts, String... excludeGroups) throws MojoExecutionException { /* * Convert each resolved artifact into a URL/classpath element. */ final ArrayList<URL> classpath = new ArrayList<URL>(); final List<String> excludes = Arrays.asList(excludeGroups); try { for (Artifact resolvedArtifact : resolvedArtifacts) { if (excludes.contains(resolvedArtifact.getGroupId())) continue; final File file = resolvedArtifact.getFile(); // System.out.println("artifact " + resolvedArtifact.toString()); if (file != null) { if (artifactIdsToInsertAtStartOfClasspath.contains(resolvedArtifact.getArtifactId())) { getLog().info("adding at the start" + file.getAbsolutePath()); // a patch? grails is full of them, insert it at the start classpath.add(0, file.toURI().toURL()); } else { // insert it at the end classpath.add(file.toURI().toURL()); } } } } catch (MalformedURLException murle) { throw new MojoExecutionException("Unable to find files", murle); } return classpath; }
private void resolveClasspath() throws MojoExecutionException { parsePatchArtifacts(); getLog() .info( "Resolving dependencies" + (useTransitives ? "" : " - warning! we are not using transitive dependencies, only those directly in the pom.xml")); resolvedArtifacts = collectAllProjectArtifacts(); /* * Remove any Grails plugins that may be in the resolved artifact set. This is because we * do not need them on the classpath, as they will be handled later on by a separate call to * "install" them. */ pluginArtifacts = removePluginArtifacts(resolvedArtifacts); pluginDirectories = new ArrayList<File>(); for (Artifact artifact : pluginArtifacts) pluginDirectories.add(getPluginDirAndInstallIfNecessary(artifact)); if (getLog().isInfoEnabled()) { for (File f : pluginDirectories) { getLog().info("plugin: " + f.getAbsolutePath()); } } classpath = generateGrailsExecutionClasspath(resolvedArtifacts); System.gc(); }
private File getPluginTargetDirOverride(Artifact plugin) { String pluginLocationOverride = System.getProperty(plugin.getGroupId() + ":" + plugin.getArtifactId()); File targetDir = null; if (pluginLocationOverride != null && pluginLocationOverride.length() > 0) { targetDir = new File(pluginLocationOverride); if (!targetDir.exists()) { getLog() .error( String.format( "Specified directory (%s) for plugin %s:%s:%s could not be found", pluginLocationOverride, plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion())); targetDir = null; } } return targetDir; }
private void printIntellijIDEASettings( DecentGrailsLauncher launcher, Field settingsField, Set<Artifact> pluginArtifacts) { try { Object settings = settingsField.get(launcher); Field configField = settings.getClass().getSuperclass().getDeclaredField("config"); configField.setAccessible(true); Object config = configField.get(settings); Map flatten = (Map) config.getClass().getDeclaredMethod("flatten").invoke(config); System.out.println(); System.out.println(SETTINGS_START_MARKER); for (Object key : flatten.keySet()) { Object value = flatten.get(key); if (value instanceof String || value instanceof GString) { String realKey = key.toString(); if (GRAILS_PROPERTY_LIST.contains(realKey)) { System.out.println(realKey + "=" + value.toString().replace('\\', '/')); } } } for (Artifact plugin : pluginArtifacts) { File targetDir = getPluginTargetDir(plugin); System.out.println( "grails.plugin.location." + getPluginName(plugin) + "=" + targetDir.getAbsolutePath().replace('\\', '/')); } System.out.println(); System.out.println(SETTINGS_END_MARKER); } catch (Exception ex) { getLog().error("Unable to get flattened configuration data", ex); } }
/** * Generates the classpath to be used by the launcher to execute the requested Grails script. * * @return An array of {@code URL} objects representing the dependencies required on the classpath * to execute the selected Grails script. * @throws MojoExecutionException if an error occurs while attempting to resolve the dependencies * and generate the classpath array. */ @SuppressWarnings("unchecked") private URL[] generateGrailsExecutionClasspath(Set<Artifact> resolvedArtifacts) throws MojoExecutionException { try { final List<URL> classpath = generateExecutionClasspath(resolvedArtifacts); // check to see if someone is adding build listeners on the classpath, and if so, bring in the // system classpath and add it to our urls // IDEA for example does this if (System.getProperty("grails.build.listeners") != null) { String cp = System.getProperty("java.class.path"); for (String c : cp.split(":")) { File f = new File(c); if (f.exists()) classpath.add(f.toURI().toURL()); } } if (System.getProperty("grails.debug.classpath") != null) { for (URL url : classpath) { getLog().info("classpath " + url.toString()); } } /* * Add the "tools.jar" to the classpath so that the Grails scripts can run native2ascii. * First assume that "java.home" points to a JRE within a JDK. NOTE that this will not * provide a valid path on Mac OSX. This is not a big deal, as the JDK on Mac OSX already * adds the required JAR's to the classpath. This logic is really only for Windows/*Unix. */ final String javaHome = System.getProperty("java.home"); File toolsJar = new File(javaHome, "../lib/tools.jar"); if (!toolsJar.exists()) { // The "tools.jar" cannot be found with that path, so // now try with the assumption that "java.home" points // to a JDK. toolsJar = new File(javaHome, "tools.jar"); } if (toolsJar.exists()) { java.net.URL url = toolsJar.toURI().toURL(); if (url != null) { classpath.add(url); } } return classpath.toArray(new URL[classpath.size()]); } catch (final Exception e) { throw new MojoExecutionException("Failed to create classpath for Grails execution.", e); } }
private String readFileAsString(File file) throws java.io.IOException { byte[] buffer = new byte[(int) file.length()]; BufferedInputStream bis = null; try { bis = new BufferedInputStream(new FileInputStream(file)); bis.read(buffer); } finally { if (bis != null) try { bis.close(); } catch (IOException ignored) { } } return new String(buffer); }
// we only need to do these once as they don't change private void doOncePerArtifact() throws MojoExecutionException { lastArtifactId = project.getArtifactId(); lastGroupId = project.getGroupId(); configureMavenProxy(); resolveClasspath(); // printClasspath("main", Arrays.asList(classpath)); grailsHomePath = (grailsHome != null) ? grailsHome.getAbsolutePath() : null; if (isWindows()) { // force console and interactive on to get around _GrailsRun.groovy windows // bug where attaches to grailsConsole.reader.add... System.setProperty("grails.console.enable.terminal", "true"); System.setProperty("grails.console.enable.interactive", "true"); } else { if (System.getProperty("grails.console.enable.terminal") == null) System.setProperty("grails.console.enable.terminal", "true"); if (System.getProperty("grails.console.enable.interactive") == null) System.setProperty("grails.console.enable.interactive", "true"); } // override the servlet factory if it is specified if (this.servletServerFactory != null) { System.setProperty("grails.server.factory", this.servletServerFactory); } // see if we are using logback and not log4j // final String logbackFilename = this.getBasedir() + "/logback.xml"; // // if (new File(logbackFilename).exists()) { // getLog().info("Found logback configuration, setting logback.xml to " + logbackFilename); // // System.setProperty("logback.configurationFile", logbackFilename); // } }
/** * Executes the requested Grails target. The "targetName" must match a known Grails script * provided by grails-scripts. * * @param targetName The name of the Grails target to execute. * @param args String of arguments to be passed to the executed Grails target. * @throws MojoExecutionException if an error occurs while attempting to execute the target. */ protected void runGrails(final String targetName, String args) throws MojoExecutionException { if (((lastArgs != null && lastArgs.equals(args)) || (lastArgs == null && args == null)) && lastTargetName != null && lastTargetName.equals(targetName)) return; lastArgs = args; lastTargetName = targetName; if (!alreadyLoaderClasspathForArtifact()) doOncePerArtifact(); else if (targetName.equals("War")) resolveClasspath(); // we have to get rid of the test rubbish getLog() .info( "Grails target: " + targetName + " raw args:" + args + " (pom says Grails Version is " + grailsVersion + ")"); InputStream currentIn = System.in; PrintStream currentOutput = System.out; try { RootLoader rootLoader = new RootLoader(addBinaryPluginWorkaround(classpath)); // see if log4j is there and if so, initialize it try { Class cls = rootLoader.loadClass("org.springframework.util.Log4jConfigurer"); invokeStaticMethod( cls, "initLogging", new Object[] {"classpath:grails-maven/log4j.properties"}); } catch (Exception ex) { getLog().info("No log4j available, good!"); } try { final DecentGrailsLauncher launcher = new DecentGrailsLauncher(rootLoader, grailsHomePath, basedir.getAbsolutePath()); launcher.setPlainOutput(true); /** * this collects the different dependency levels (compile, runtime, test) and puts them into * the correct arrays to pass through to the Grails script launcher. If using Maven, you * should *never* see an Ivy message and if you do, immediately stop your build, figure out * the incorrect dependency, delete the ~/.ivy2 directory and try again. */ Field settingsField = launcher.getClass().getDeclaredField("settings"); settingsField.setAccessible(true); configureBuildSettings( launcher, resolvedArtifacts, settingsField, rootLoader.loadClass("grails.util.BuildSettings"), args); syncAppVersion(); installGrailsPlugins( pluginDirectories, launcher, settingsField, rootLoader.loadClass("grails.util.AbstractBuildSettings")); // If the command is running in non-interactive mode, we // need to pass on the relevant argument. if (this.nonInteractive) { args = (args != null) ? "--non-interactive " + args : "--non-interactive "; } // consuming the standard output after execution via Maven. args = (args != null) ? "--plain-output " + args : "--plain-output"; args = (args != null) ? "--stacktrace " + args : "--stacktrace"; args = (args != null) ? "--verboseCompile " + args : "--verboseCompile"; if (env == null) System.clearProperty("grails.env"); else System.setProperty("grails.env", env); getLog() .info( "grails -Dgrails.env=" + (env == null ? "dev" : env) + " " + targetName.toLowerCase() + " " + args); int retval; if ("true".equals(System.getProperty("print.grails.settings")) || "ideaprintprojectsettings".equalsIgnoreCase(targetName)) { printIntellijIDEASettings(launcher, settingsField, pluginArtifacts); } else { if ("interactive".equals(targetName)) retval = launcher.launch("", "", env); else retval = launcher.launch(targetName, args, env); if (retval != 0) { throw new MojoExecutionException("Grails returned non-zero value: " + retval); } } } catch (final MojoExecutionException ex) { // Simply rethrow it. throw ex; } catch (final Exception ex) { getLog().error(ex); throw new MojoExecutionException("Unable to start Grails", ex); } rootLoader = null; } catch (MalformedURLException mfe) { throw new MojoExecutionException("Unable to start Grails", mfe); } finally { System.setIn(currentIn); System.setOut(currentOutput); } System.gc(); // try and help with memory issues }
private File getPluginDirAndInstallIfNecessary(final Artifact plugin) throws MojoExecutionException { boolean targetDirOverridden = true; File targetDir = getPluginTargetDirOverride(plugin); if (targetDir == null) { targetDirOverridden = false; targetDir = getPluginTargetDirCentral(plugin); } String pluginName = getPluginName(plugin); final String pluginVersion = plugin.getVersion(); boolean snapshot = pluginVersion.endsWith("-SNAPSHOT"); if (snapshot && plugin .getFile() .getAbsolutePath() .endsWith("target" + File.separator + "classes")) { // multi module build targetDir = plugin.getFile().getParentFile().getParentFile(); getLog() .info( String.format( "Plugin %s:%s is coming from a multi-module dependency (%s)", pluginName, pluginVersion, targetDir.getAbsolutePath())); } else if ((!snapshot && !targetDir.exists()) || (snapshot && !targetDirOverridden)) { // Unpack the plugin if it hasn't already been or if its a SNAPSHOT and not overridden by // -Dflag // Ideally we need to now do two things (a) see if we are running JDK7 // and (b) determine if -Dplugin.groupId.artifactId has been set - if this is so, we want to // do a Files.createLink // to the directory specified by the -D flag. We should probably also check if the targetDir // is a link and // the -Dflag hasn't been set, in which case we'd want to remove the link and install the // plugin (and let the user // know this has happened. // We wouldn't actually want this to be allowed when doing a release however.... So people // should make sure they don't // specify them, they they'll be installed. getLog() .info( String.format( "Installing Plugin %s:%s into (%s)", pluginName, pluginVersion, targetDir.getAbsolutePath())); targetDir.mkdirs(); final ZipUnArchiver unzipper = new ZipUnArchiver(); unzipper.enableLogging(new ConsoleLogger(Logger.LEVEL_ERROR, "zip-unarchiver")); unzipper.setSourceFile(plugin.getFile()); unzipper.setDestDirectory(targetDir); unzipper.setOverwrite(true); try { unzipper.extract(); } catch (ArchiverException e) { throw new MojoExecutionException("Unable to extract zip", e); } try { File inputPom = new File(plugin.getFile().getParentFile(), pluginName + "-" + pluginVersion + ".pom"); File outputPom = new File(targetDir, "pom.xml"); getLog() .info( String.format( "copying %s to %s", inputPom.getAbsolutePath(), outputPom.getAbsolutePath())); FileReader fr = new FileReader(inputPom); FileWriter fw = new FileWriter(outputPom); IOUtils.copy(fr, fw); fw.flush(); fw.close(); fr.close(); } catch (IOException e) { throw new MojoExecutionException("Unable to copy pom.xml file"); } } else { getLog() .info( String.format( "Plugin %s:%s already installed (%s)", pluginName, pluginVersion, targetDir.getAbsolutePath())); } return targetDir; }