private int executeCommand(CommandLine commandLine, String scriptName, String env) { @SuppressWarnings("hiding") GrailsConsole console = GrailsConsole.getInstance(); // Load the BuildSettings file for this project if it exists. Note // that this does not load any environment-specific settings. try { System.setProperty("disable.grails.plugin.transform", "true"); console.updateStatus("Loading Grails " + settings.getGrailsVersion()); settings.loadConfig(); System.setProperty( "springloaded.directoriesContainingReloadableCode", settings.getClassesDir().getAbsolutePath() + ',' + settings.getPluginClassesDir().getAbsolutePath()); } catch (Exception e) { console.error("There was an error loading the BuildConfig: " + e.getMessage(), e); System.exit(1); } finally { System.setProperty("disable.grails.plugin.transform", "false"); } // Add some extra binding variables that are now available. // settings.setGrailsEnv(env); // settings.setDefaultEnv(useDefaultEnv); BuildSettingsHolder.setSettings(settings); return callPluginOrGrailsScript(commandLine, scriptName, env); }
private String askUserForBestMatch(String scriptName, List<String> topMatches) { @SuppressWarnings("hiding") GrailsConsole console = GrailsConsole.getInstance(); console.addStatus("Script '" + scriptName + "' not found, did you mean:"); int i = 0; for (String s : topMatches) { console.log(" " + ++i + ") " + s); } int attempts = 0; while (true) { String selection = console.userInput("Please make a selection or enter Q to quit: "); if ("Q".equalsIgnoreCase(selection)) { System.exit(0); } try { int number = Integer.parseInt(selection); if (number > 0 && number <= topMatches.size()) { return topMatches.get(number - 1); } } catch (NumberFormatException ignored) { // ignored } attempts++; if (attempts > 4) { exitWithError("Selection not found.", null); } } }
private static void exitWithError(String error, Throwable t) { if (t != null) { GrailsConsole.getInstance().error(error, t); } else { GrailsConsole.getInstance().error(error); } System.exit(1); }
private GrailsConsole getConsole(CommandLine commandLine) { GrailsConsole console = GrailsConsole.getInstance(); // Set the console display properties console.setAnsiEnabled(!commandLine.hasOption(CommandLine.NOANSI_ARGUMENT)); console.setStacktrace(commandLine.hasOption(CommandLine.STACKTRACE_ARGUMENT)); console.setVerbose(commandLine.hasOption(CommandLine.VERBOSE_ARGUMENT)); return console; }
private static void exitWithError(String error, Throwable t) { GrailsConsole grailsConsole = GrailsConsole.getInstance(); if (t == null) { grailsConsole.error(error); } else { grailsConsole.error(error, t); } grailsConsole.flush(); System.exit(1); }
/** * Interactive prompt that can be used by any part of the build. Echos the given message to the * console and waits for user input that matches either 'y' or 'n'. Returns <code>true</code> if * the user enters 'y', <code>false</code> otherwise. */ public boolean confirmInput(String message, String code) { if (code == null) code = "confirm.message"; GrailsConsole grailsConsole = GrailsConsole.getInstance(); if (!isInteractive) { grailsConsole.error( "Cannot ask for input when --non-interactive flag is passed. Please switch back to interactive mode."); exit(1); } return "y".equalsIgnoreCase(grailsConsole.userInput(message, new String[] {"y", "n"})); }
private static ScriptAndArgs processArgumentsAndReturnScriptName(CommandLine commandLine) { if (commandLine.hasOption(CommandLine.VERBOSE_ARGUMENT)) { GrailsConsole.getInstance().setVerbose(true); } if (commandLine.hasOption(CommandLine.STACKTRACE_ARGUMENT)) { GrailsConsole.getInstance().setStacktrace(true); } processSystemArguments(commandLine); return processAndReturnArguments(commandLine); }
/** * Times the execution of a closure, which can include a target. For example, * * <p>profile("compile", compile) * * <p>where 'compile' is the target. */ public void profile(String name, Closure<?> callable) { if (enableProfile) { long now = System.currentTimeMillis(); GrailsConsole console = GrailsConsole.getInstance(); console.addStatus("Profiling [" + name + "] start"); callable.call(); long then = System.currentTimeMillis() - now; console.addStatus("Profiling [" + name + "] finish. Took " + then + " ms"); } else { callable.call(); } }
private int executeScriptFile( CommandLine commandLine, String scriptName, String env, GantBinding binding, Resource scriptFile) { // We can now safely set the default environment String scriptFileName = getScriptNameFromFile(scriptFile); setRunningEnvironment(commandLine, env); binding.setVariable("scriptName", scriptFileName); // Setup the script to call. ScriptBindingInitializer bindingInitializer = new ScriptBindingInitializer(commandLine, settings, pluginPathSupport, isInteractive); Gant gant = new Gant(bindingInitializer.initBinding(binding, scriptName), classLoader); gant.setUseCache(true); gant.setCacheDirectory(scriptCacheDir); GantResult result = null; try { gant.loadScript(scriptFile.getURL()); result = executeWithGantInstance(gant, DO_NOTHING_CLOSURE); return result.exitCode; } catch (IOException e) { console.error("I/O exception loading script [" + e.getMessage() + "]: " + e.getMessage()); return 1; } finally { cleanup(result, binding); } }
protected void initializeLogging() { if (settings.getGrailsHome() == null) { return; } try { Class<?> cls = Thread.currentThread() .getContextClassLoader() .loadClass("org.apache.log4j.PropertyConfigurator"); Method configure = cls.getMethod("configure", URL.class); configure.setAccessible(true); File f = new File(settings.getGrailsHome() + "/grails-scripts/src/main/scripts/log4j.properties"); if (f.exists()) { configure.invoke(cls, f.toURI().toURL()); } else { f = new File(settings.getGrailsHome() + "/scripts/log4j.properties"); configure.invoke(cls, f.toURI().toURL()); } } catch (Throwable e) { console.verbose( "Log4j was not found on the classpath and will not be used for command line logging. Cause " + e.getClass().getName() + ": " + e.getMessage()); } }
private int handleScriptExecutedOutsideProjectError() { console.error( settings.getBaseDir().getPath() + " does not appear to be part of a Grails application."); console.error("The following commands are supported outside of a project:"); Collections.sort( scriptsAllowedOutsideOfProject, new Comparator<Resource>() { public int compare(Resource resource, Resource resource1) { return resource.getFilename().compareTo(resource1.getFilename()); } }); for (Resource file : scriptsAllowedOutsideOfProject) { console.log("\t" + GrailsNameUtils.getScriptName(file.getFilename())); } console.addStatus("Run 'grails help' for a complete list of available scripts."); return -1; }
@Override public void fireTestStarted(Description description) throws StoppedByUserException { int progress = ++this.progress; if (progress > total) { total = progress; } console.indicateProgress(progress, total); super.fireTestStarted(description); }
@Override public void fireTestFailure(Failure failure) { console.error("Failure: ", failure.getDescription().getDisplayName()); Throwable exception = failure.getException(); if (exception == null) { console.error(failure.getMessage()); } else { StackTraceFilterer filterer = new DefaultStackTraceFilterer(); filterer.setCutOffPackage("org.junit"); filterer.filter(exception, true); StringWriter sw = new StringWriter(); PrintWriter ps = new PrintWriter(sw); exception.printStackTrace(ps); console.error("", sw.toString()); } super.fireTestFailure(failure); }
private void initializeState(String scriptName) { // The directory where scripts are cached. this.scriptCacheDir = new File(settings.getProjectWorkDir(), "scriptCache"); this.console = GrailsConsole.getInstance(); // Add the remaining JARs (from 'grailsHome', the app, and // the plugins) to the root loader. boolean skipPlugins = scriptName != null && ("UninstallPlugin".equals(scriptName) || "InstallPlugin".equals(scriptName)); console.updateStatus("Configuring classpath"); ClasspathConfigurer configurer = new ClasspathConfigurer(pluginPathSupport, settings, skipPlugins); if ("DependencyReport".equals(scriptName) || "Upgrade".equals(scriptName)) { configurer.setExitOnResolveError(false); } this.classLoader = configurer.configuredClassLoader(); initializeLogging(); }
private int attemptPrecompiledScriptExecute( CommandLine commandLine, String scriptName, String env, GantBinding binding, List<File> allScripts) { console.updateStatus("Running pre-compiled script"); // Must be called before the binding is initialised. setRunningEnvironment(commandLine, env); // Get Gant to load the class by name using our class loader. ScriptBindingInitializer bindingInitializer = new ScriptBindingInitializer( commandLine, classLoader, settings, pluginPathSupport, isInteractive); Gant gant = new Gant(bindingInitializer.initBinding(binding, scriptName), classLoader); try { loadScriptClass(gant, scriptName); } catch (ScriptNotFoundException e) { if (!isInteractive || InteractiveMode.isActive()) { throw e; } scriptName = fixScriptName(scriptName, allScripts); if (scriptName == null) { throw e; } try { loadScriptClass(gant, scriptName); } catch (ScriptNotFoundException ce) { return executeScriptWithCaching(commandLine, scriptName, env); } // at this point if they were calling a script that has a non-default // env (e.g. war or test-app) it wouldn't have been correctly set, so // set it now, but only if they didn't specify the env (e.g. "grails test war" -> "grails test // war") if (Boolean.TRUE.toString().equals(System.getProperty(Environment.DEFAULT))) { commandLine.setCommand(GrailsNameUtils.getScriptName(scriptName)); env = commandLine.lookupEnvironmentForCommand(); binding.setVariable("grailsEnv", env); settings.setGrailsEnv(env); System.setProperty(Environment.KEY, env); settings.setDefaultEnv(false); System.setProperty(Environment.DEFAULT, Boolean.FALSE.toString()); } } return executeWithGantInstance(gant, DO_NOTHING_CLOSURE, binding).exitCode; }
public void loadEventsScript(File eventScript) { if (eventScript == null) { return; } GrailsConsole console = GrailsConsole.getInstance(); try { Class<?> scriptClass = classLoader.parseClass(eventScript); if (scriptClass == null) { console.error("Could not load event script (script may be empty): " + eventScript); return; } Script script = (Script) scriptClass.newInstance(); script.setBinding( new Binding(binding.getVariables()) { @SuppressWarnings("rawtypes") @Override public void setVariable(String var, Object o) { final Matcher matcher = EVENT_NAME_PATTERN.matcher(var); if (matcher.matches() && (o instanceof Closure)) { String eventName = matcher.group(1); List<Closure> hooks = globalEventHooks.get(eventName); if (hooks == null) { hooks = new ArrayList<Closure>(); globalEventHooks.put(eventName, hooks); } hooks.add((Closure<?>) o); } super.setVariable(var, o); } }); script.run(); } catch (Throwable e) { StackTraceUtils.deepSanitize(e); console.error( "Error loading event script from file [" + eventScript + "] " + e.getMessage(), e); } }
/** Exits the build immediately with a given exit code. */ public void exit(int code) { if (buildEventListener != null) { buildEventListener.triggerEvent("Exiting", code); } // Prevent system.exit during unit/integration testing if (System.getProperty("grails.cli.testing") != null || System.getProperty("grails.disable.exit") != null) { throw new ScriptExitException(code); } GrailsConsole.getInstance().flush(); System.exit(code); }
public void handleInput(InputRequest inputRequest) throws BuildException { String[] validInputs = null; if (inputRequest instanceof MultipleChoiceInputRequest) { @SuppressWarnings("unchecked") List<String> choices = ((MultipleChoiceInputRequest) inputRequest).getChoices(); validInputs = choices.toArray(new String[choices.size()]); } String result = GrailsConsole.getInstance().userInput(inputRequest.getPrompt(), validInputs); if (result == null || result.length() == 0) { result = inputRequest.getDefaultValue(); } inputRequest.setInput(result); }
@SuppressWarnings({"unchecked", "rawtypes"}) private int executeScriptWithCaching(CommandLine commandLine, String scriptName, String env) { List<File> potentialScripts; List<File> allScripts = getAvailableScripts(); GantBinding binding = new GantBinding(); binding.setVariable("scriptName", scriptName); setDefaultInputStream(binding); // Now find what scripts match the one requested by the user. potentialScripts = getPotentialScripts(scriptName, allScripts); if (potentialScripts.size() == 0) { try { File aliasFile = new File(settings.getUserHome(), ".grails/.aliases"); if (aliasFile.exists()) { Properties aliasProperties = new Properties(); aliasProperties.load(new FileReader(aliasFile)); if (aliasProperties.containsKey(commandLine.getCommandName())) { String aliasValue = (String) aliasProperties.get(commandLine.getCommandName()); String[] aliasPieces = aliasValue.split(" "); String commandName = aliasPieces[0]; String correspondingScriptName = GrailsNameUtils.getNameFromScript(commandName); potentialScripts = getPotentialScripts(correspondingScriptName, allScripts); if (potentialScripts.size() > 0) { String[] additionalArgs = new String[aliasPieces.length - 1]; System.arraycopy(aliasPieces, 1, additionalArgs, 0, additionalArgs.length); insertArgumentsInFrontOfExistingArguments(commandLine, additionalArgs); } } } } catch (Exception e) { console.error(e); } } // First try to load the script from its file. If there is no // file, then attempt to load it as a pre-compiled script. If // that fails, then let the user know and then exit. if (potentialScripts.size() > 0) { potentialScripts = (List) DefaultGroovyMethods.unique(potentialScripts); final File scriptFile = potentialScripts.get(0); if (!isGrailsProject() && !isExternalScript(scriptFile)) { return handleScriptExecutedOutsideProjectError(); } return executeScriptFile(commandLine, scriptName, env, binding, scriptFile); } return attemptPrecompiledScriptExecute(commandLine, scriptName, env, binding, allScripts); }
protected void initializeLogging() { if (settings.getGrailsHome() == null) { return; } try { org.springframework.util.Log4jConfigurer.initLogging( "file:" + settings.getGrailsHome() + "/scripts/log4j.properties"); } catch (Throwable e) { console.verbose( "Log4j was not found on the classpath and will not be used for command line logging. Cause " + e.getClass().getName() + ": " + e.getMessage()); } }
/** * A RunNotifier that logs the the GrailsConsole. * * @author Graeme Rocher * @since 2.0 */ public class GrailsTestRunNotifier extends RunNotifier { int progress = 0; int total; private GrailsConsole console = GrailsConsole.getInstance(); public GrailsTestRunNotifier(int total) { this.total = total; } @Override public void fireTestRunFinished(Result result) { super.fireTestRunFinished(result); } @Override public void fireTestStarted(Description description) throws StoppedByUserException { int progress = ++this.progress; if (progress > total) { total = progress; } console.indicateProgress(progress, total); super.fireTestStarted(description); } @Override public void fireTestFailure(Failure failure) { console.error("Failure: ", failure.getDescription().getDisplayName()); Throwable exception = failure.getException(); if (exception == null) { console.error(failure.getMessage()); } else { StackTraceFilterer filterer = new DefaultStackTraceFilterer(); filterer.setCutOffPackage("org.junit"); filterer.filter(exception, true); StringWriter sw = new StringWriter(); PrintWriter ps = new PrintWriter(sw); exception.printStackTrace(ps); console.error("", sw.toString()); } super.fireTestFailure(failure); } }
protected boolean canWrite(File testFile) { if (overwrite || !testFile.exists()) { return true; } try { String relative = makeRelativeIfPossible(testFile.getAbsolutePath(), basedir); String response = GrailsConsole.getInstance() .userInput( "File " + relative + " already exists. Overwrite?", new String[] {"y", "n", "a"}); overwrite = overwrite || "a".equals(response); return overwrite || "y".equals(response); } catch (Exception e) { // failure to read from standard in means we're probably running from an automation tool like // a build server return true; } }
/** * Handles Grails command line interface for running scripts. * * @author Graeme Rocher * @since 0.4 */ public class GrailsScriptRunner { private static final Pattern scriptFilePattern = Pattern.compile("^[^_]\\w+\\.groovy$"); private static InputStream originalIn; private static PrintStream originalOut; @SuppressWarnings("rawtypes") public static final Closure DO_NOTHING_CLOSURE = new Closure(GrailsScriptRunner.class) { private static final long serialVersionUID = 1L; @Override public Object call(Object arguments) { return null; } @Override public Object call() { return null; } @Override public Object call(Object... args) { return null; } }; private PluginPathDiscoverySupport pluginPathSupport; private BuildSettings settings; private PrintStream out = System.out; private boolean isInteractive = true; private URLClassLoader classLoader; private GrailsConsole console = GrailsConsole.getInstance(); private File scriptCacheDir; private final List<Resource> scriptsAllowedOutsideOfProject = new ArrayList<Resource>(); public GrailsScriptRunner() { this(new BuildSettings()); } public GrailsScriptRunner(String grailsHome) { this(new BuildSettings(new File(grailsHome))); } public GrailsScriptRunner(BuildSettings settings) { if (originalIn == null) { originalIn = System.in; originalOut = System.out; } this.settings = settings; this.pluginPathSupport = new PluginPathDiscoverySupport(settings); } public void setInteractive(boolean interactive) { isInteractive = interactive; } /** * Evaluate the arguments to get the name of the script to execute, which environment to run it * in, and the arguments to pass to the script. This also evaluates arguments of the form * "-Dprop=value" and creates system properties from each one. * * @param args Command line arguments */ public static void main(String[] args) { originalIn = System.in; originalOut = System.out; CommandLineParser parser = getCommandLineParser(); GrailsConsole console = GrailsConsole.getInstance(); CommandLine commandLine; try { if (args.length == 0) { commandLine = new DefaultCommandLine(); } else { commandLine = parser.parseString(args[0]); if (commandLine.hasOption(CommandLine.NOANSI_ARGUMENT)) { console.setAnsiEnabled(false); } } } catch (ParseException e) { console.error("Error processing command line arguments: " + e.getMessage()); System.exit(1); return; } String version = System.getProperty("grails.version"); ScriptAndArgs script = processArgumentsAndReturnScriptName(commandLine); // Get hold of the GRAILS_HOME environment variable if it is available. String grailsHome = System.getProperty("grails.home"); // Now we can pick up the Grails version from the Ant project properties. BuildSettings build = null; try { build = new BuildSettings(new File(grailsHome)); build.setModified(commandLine.hasOption(CommandLine.REFRESH_DEPENDENCIES_ARGUMENT)); build.setOffline(commandLine.hasOption(CommandLine.OFFLINE_ARGUMENT)); if (build.getRootLoader() == null) { build.setRootLoader((URLClassLoader) GrailsScriptRunner.class.getClassLoader()); } } catch (Exception e) { exitWithError( "An error occurred loading the grails-app/conf/BuildConfig.groovy file: " + e.getMessage(), null); } // Check that Grails' home actually exists. final File grailsHomeInSettings = build.getGrailsHome(); if (grailsHomeInSettings == null || !grailsHomeInSettings.exists()) { exitWithError("Grails' installation directory not found: " + build.getGrailsHome(), null); } if (commandLine.hasOption(CommandLine.VERSION_ARGUMENT)) { console.log("Grails version: " + build.getGrailsVersion()); System.exit(0); } if (commandLine.hasOption(CommandLine.HELP_ARGUMENT)) { console.log(parser.getHelpMessage()); System.exit(0); } // If there aren't any arguments, then we don't have a command // to execute, so enter "interactive mode" boolean resolveDeps = commandLine.hasOption(CommandLine.REFRESH_DEPENDENCIES_ARGUMENT); if (resolveDeps) { if (commandLine.hasOption("include-source")) { build.setIncludeSource(true); } if (commandLine.hasOption("include-javadoc")) { build.setIncludeJavadoc(true); } } GrailsScriptRunner scriptRunner = new GrailsScriptRunner(build); scriptRunner.setInteractive(!commandLine.hasOption(CommandLine.NON_INTERACTIVE_ARGUMENT)); if ("Interactive".equals(script.name)) { console.error( "The 'interactive' script is deprecated; to run in interactive mode just omit the script name"); script.name = null; } if (script.name == null) { console.updateStatus( "Loading Grails " + (version != null ? version : build.getGrailsVersion())); build.loadConfig(); if (resolveDeps) { ClasspathConfigurer.cleanResolveCache(build); } scriptRunner.initializeState(); try { new InteractiveMode(build, scriptRunner).run(); } catch (Throwable e) { console.error("Interactive mode exited with error: " + e.getMessage(), e); } } else { console.getCategory().push(script.inputName); console.verbose("Base Directory: " + build.getBaseDir().getPath()); try { int exitCode = scriptRunner.executeCommand(commandLine, script.name, script.env); System.exit(exitCode); } catch (ScriptNotFoundException ex) { console.error("Script not found: " + ex.getScriptName()); } catch (Throwable t) { String msg = "Error executing script " + script.name + ": " + t.getMessage(); exitWithError(msg, t); } } } public static CommandLineParser getCommandLineParser() { CommandLineParser parser = new CommandLineParser(); parser.addOption( CommandLine.REFRESH_DEPENDENCIES_ARGUMENT, "Whether to force a resolve of dependencies (skipping any caching)"); parser.addOption(CommandLine.VERBOSE_ARGUMENT, "Enable verbose output"); parser.addOption( CommandLine.OFFLINE_ARGUMENT, "Indicates that Grails should not connect to any remote servers during processing of the build"); parser.addOption(CommandLine.STACKTRACE_ARGUMENT, "Enable stack traces in output"); parser.addOption(CommandLine.AGENT_ARGUMENT, "Enable the reloading agent"); parser.addOption( CommandLine.NON_INTERACTIVE_ARGUMENT, "Whether to allow the command line to request input"); parser.addOption(CommandLine.HELP_ARGUMENT, "Command line help"); parser.addOption(CommandLine.VERSION_ARGUMENT, "Current Grails version"); parser.addOption(CommandLine.NOANSI_ARGUMENT, "Disables ANSI output"); return parser; } private static void exitWithError(String error, Throwable t) { if (t != null) { GrailsConsole.getInstance().error(error, t); } else { GrailsConsole.getInstance().error(error); } System.exit(1); } private static ScriptAndArgs processArgumentsAndReturnScriptName(CommandLine commandLine) { if (commandLine.hasOption(CommandLine.VERBOSE_ARGUMENT)) { GrailsConsole.getInstance().setVerbose(true); } if (commandLine.hasOption(CommandLine.STACKTRACE_ARGUMENT)) { GrailsConsole.getInstance().setStacktrace(true); } processSystemArguments(commandLine); return processAndReturnArguments(commandLine); } private static ScriptAndArgs processAndReturnArguments(CommandLine commandLine) { ScriptAndArgs info = new ScriptAndArgs(); if (Environment.isSystemSet()) { info.env = Environment.getCurrent().getName(); } else if (commandLine.getEnvironment() != null) { info.env = commandLine.getEnvironment(); } info.inputName = commandLine.getCommandName(); info.name = GrailsNameUtils.getNameFromScript(commandLine.getCommandName()); info.args = commandLine.getRemainingArgsString(); return info; } private static void processSystemArguments(CommandLine allArgs) { Properties systemProps = allArgs.getSystemProperties(); if (systemProps != null) { for (Map.Entry<Object, Object> entry : systemProps.entrySet()) { System.setProperty(entry.getKey().toString(), entry.getValue().toString()); } } } public PrintStream getOut() { return out; } public void setOut(PrintStream outputStream) { this.out = outputStream; } public int executeCommand(String scriptName, String args) { return executeCommand(scriptName, args, null); } public int executeCommand(String scriptName, String args, String env) { // Populate the root loader with all libraries that this app // depends on. If a root loader doesn't exist yet, create it now. if (args != null) { System.setProperty("grails.cli.args", args.replace(' ', '\n')); } else { // If GrailsScriptRunner is executed more than once in a // single JVM, we have to make sure that the CLI args are reset. System.setProperty("grails.cli.args", ""); } CommandLineParser parser = getCommandLineParser(); CommandLine commandLine = parser.parseString(scriptName, args); return executeCommand(commandLine, scriptName, env); } private int executeCommand(CommandLine commandLine, String scriptName, String env) { @SuppressWarnings("hiding") GrailsConsole console = GrailsConsole.getInstance(); // Load the BuildSettings file for this project if it exists. Note // that this does not load any environment-specific settings. try { System.setProperty("disable.grails.plugin.transform", "true"); console.updateStatus("Loading Grails " + settings.getGrailsVersion()); settings.loadConfig(); System.setProperty( "springloaded.directoriesContainingReloadableCode", settings.getClassesDir().getAbsolutePath() + ',' + settings.getPluginClassesDir().getAbsolutePath()); } catch (Exception e) { console.error("There was an error loading the BuildConfig: " + e.getMessage(), e); System.exit(1); } finally { System.setProperty("disable.grails.plugin.transform", "false"); } // Add some extra binding variables that are now available. // settings.setGrailsEnv(env); // settings.setDefaultEnv(useDefaultEnv); BuildSettingsHolder.setSettings(settings); return callPluginOrGrailsScript(commandLine, scriptName, env); } private void setRunningEnvironment(CommandLine commandLine, String env) { // Get the default environment if one hasn't been set. System.setProperty("base.dir", settings.getBaseDir().getPath()); if (env != null) { // Add some extra binding variables that are now available. settings.setGrailsEnv(env); settings.setDefaultEnv(false); } else { // Add some extra binding variables that are now available. settings.setGrailsEnv(commandLine.getEnvironment()); settings.setDefaultEnv(!commandLine.isEnvironmentSet()); } } private int callPluginOrGrailsScript(CommandLine commandLine, String scriptName, String env) { initializeState(scriptName); return executeScriptWithCaching(commandLine, scriptName, env); } public int executeScriptWithCaching(CommandLine commandLine) { processSystemArguments(commandLine); System.setProperty("grails.cli.args", commandLine.getRemainingArgsLineSeparated()); return executeScriptWithCaching( commandLine, GrailsNameUtils.getNameFromScript(commandLine.getCommandName()), commandLine.getEnvironment()); } @SuppressWarnings({"unchecked", "rawtypes"}) private int executeScriptWithCaching(CommandLine commandLine, String scriptName, String env) { List<Resource> potentialScripts; List<Resource> allScripts = getAvailableScripts(); GantBinding binding = new GantBinding(); binding.setVariable("scriptName", scriptName); setDefaultInputStream(binding); // Now find what scripts match the one requested by the user. boolean exactMatchFound = false; potentialScripts = new ArrayList<Resource>(); for (Resource scriptPath : allScripts) { String scriptFileName = scriptPath .getFilename() .substring(0, scriptPath.getFilename().length() - 7); // trim .groovy extension if (scriptFileName.endsWith("_")) { scriptsAllowedOutsideOfProject.add(scriptPath); scriptFileName = scriptFileName.substring(0, scriptFileName.length() - 1); } if (scriptFileName.equals(scriptName)) { potentialScripts.add(scriptPath); exactMatchFound = true; continue; } if (!exactMatchFound && ScriptNameResolver.resolvesTo(scriptName, scriptFileName)) { potentialScripts.add(scriptPath); } } // First try to load the script from its file. If there is no // file, then attempt to load it as a pre-compiled script. If // that fails, then let the user know and then exit. if (potentialScripts.size() > 0) { potentialScripts = (List) DefaultGroovyMethods.unique(potentialScripts); final Resource scriptFile = potentialScripts.get(0); if (!isGrailsProject() && !isExternalScript(scriptFile)) { return handleScriptExecutedOutsideProjectError(); } return executeScriptFile(commandLine, scriptName, env, binding, scriptFile); } return attemptPrecompiledScriptExecute(commandLine, scriptName, env, binding, allScripts); } private int attemptPrecompiledScriptExecute( CommandLine commandLine, String scriptName, String env, GantBinding binding, List<Resource> allScripts) { console.updateStatus("Running pre-compiled script"); // Must be called before the binding is initialised. setRunningEnvironment(commandLine, env); // Get Gant to load the class by name using our class loader. ScriptBindingInitializer bindingInitializer = new ScriptBindingInitializer(commandLine, settings, pluginPathSupport, isInteractive); Gant gant = new Gant(bindingInitializer.initBinding(binding, scriptName), classLoader); try { loadScriptClass(gant, scriptName); } catch (ScriptNotFoundException e) { if (isInteractive && !InteractiveMode.isActive()) { scriptName = fixScriptName(scriptName, allScripts); if (scriptName == null) { throw e; } loadScriptClass(gant, scriptName); // at this point if they were calling a script that has a non-default // env (e.g. war or test-app) it wouldn't have been correctly set, so // set it now, but only if they didn't specify the env (e.g. "grails test war" -> "grails // test war") if (Boolean.TRUE.toString().equals(System.getProperty(Environment.DEFAULT))) { commandLine.setCommand(GrailsNameUtils.getScriptName(scriptName)); env = commandLine.lookupEnvironmentForCommand(); binding.setVariable("grailsEnv", env); settings.setGrailsEnv(env); System.setProperty(Environment.KEY, env); settings.setDefaultEnv(false); System.setProperty(Environment.DEFAULT, Boolean.FALSE.toString()); } } else { throw e; } } return executeWithGantInstance(gant, DO_NOTHING_CLOSURE).exitCode; } private int executeScriptFile( CommandLine commandLine, String scriptName, String env, GantBinding binding, Resource scriptFile) { // We can now safely set the default environment String scriptFileName = getScriptNameFromFile(scriptFile); setRunningEnvironment(commandLine, env); binding.setVariable("scriptName", scriptFileName); // Setup the script to call. ScriptBindingInitializer bindingInitializer = new ScriptBindingInitializer(commandLine, settings, pluginPathSupport, isInteractive); Gant gant = new Gant(bindingInitializer.initBinding(binding, scriptName), classLoader); gant.setUseCache(true); gant.setCacheDirectory(scriptCacheDir); GantResult result = null; try { gant.loadScript(scriptFile.getURL()); result = executeWithGantInstance(gant, DO_NOTHING_CLOSURE); return result.exitCode; } catch (IOException e) { console.error("I/O exception loading script [" + e.getMessage() + "]: " + e.getMessage()); return 1; } finally { cleanup(result, binding); } } @SuppressWarnings("rawtypes") private void cleanup(GantResult result, GantBinding binding) { if (result != null) { Class cls = GantMetaClass.class; try { Field methodsInvoked = cls.getDeclaredField("methodsInvoked"); methodsInvoked.setAccessible(true); Set methodsInvokedSet = (Set) methodsInvoked.get(cls); if (methodsInvokedSet != null) { methodsInvokedSet.clear(); } } catch (NoSuchFieldException e) { // ignore } catch (IllegalAccessException e) { // ignore } } System.setIn(originalIn); System.setOut(originalOut); GrailsPluginUtils.clearCaches(); Map variables = binding.getVariables(); Object pluginsSettingsObject = variables.get("pluginsSettings"); if (pluginsSettingsObject instanceof PluginBuildSettings) { ((PluginBuildSettings) pluginsSettingsObject).clearCache(); } GroovySystem.getMetaClassRegistry().removeMetaClass(GantBinding.class); GroovySystem.getMetaClassRegistry().removeMetaClass(Gant.class); } public void initializeState() { initializeState(null); } private void initializeState(String scriptName) { // The directory where scripts are cached. this.scriptCacheDir = new File(settings.getProjectWorkDir(), "scriptCache"); this.console = GrailsConsole.getInstance(); // Add the remaining JARs (from 'grailsHome', the app, and // the plugins) to the root loader. boolean skipPlugins = scriptName != null && ("UninstallPlugin".equals(scriptName) || "InstallPlugin".equals(scriptName)); console.updateStatus("Configuring classpath"); ClasspathConfigurer configurer = new ClasspathConfigurer(pluginPathSupport, settings, skipPlugins); if ("DependencyReport".equals(scriptName) || "Upgrade".equals(scriptName)) { configurer.setExitOnResolveError(false); } this.classLoader = configurer.configuredClassLoader(); initializeLogging(); } private int handleScriptExecutedOutsideProjectError() { console.error( settings.getBaseDir().getPath() + " does not appear to be part of a Grails application."); console.error("The following commands are supported outside of a project:"); Collections.sort( scriptsAllowedOutsideOfProject, new Comparator<Resource>() { public int compare(Resource resource, Resource resource1) { return resource.getFilename().compareTo(resource1.getFilename()); } }); for (Resource file : scriptsAllowedOutsideOfProject) { console.log("\t" + GrailsNameUtils.getScriptName(file.getFilename())); } console.addStatus("Run 'grails help' for a complete list of available scripts."); return -1; } protected void initializeLogging() { if (settings.getGrailsHome() == null) { return; } try { org.springframework.util.Log4jConfigurer.initLogging( "file:" + settings.getGrailsHome() + "/scripts/log4j.properties"); } catch (Throwable e) { console.verbose( "Log4j was not found on the classpath and will not be used for command line logging. Cause " + e.getClass().getName() + ": " + e.getMessage()); } } private void setDefaultInputStream(GantBinding binding) { // Gant does not initialise the default input stream for // the Ant project, so we manually do it here. AntBuilder antBuilder = (AntBuilder) binding.getVariable("ant"); Project p = antBuilder.getAntProject(); try { System.setIn(originalIn); p.setInputHandler(new CommandLineInputHandler()); p.setDefaultInputStream(originalIn); } catch (NoSuchMethodError nsme) { // will only happen due to a bug in JRockit // note - the only approach that works is to loop through the public methods for (Method m : p.getClass().getMethods()) { if ("setDefaultInputStream".equals(m.getName()) && m.getParameterTypes().length == 1 && InputStream.class.equals(m.getParameterTypes()[0])) { try { m.invoke(p, originalIn); break; } catch (Exception e) { // shouldn't happen, but let it bubble up to the catch(Throwable) throw new RuntimeException(e); } } } } } private void loadScriptClass(Gant gant, String scriptName) { try { // try externalized script first gant.loadScriptClass(scriptName + "_"); } catch (Exception e) { try { gant.loadScriptClass(scriptName); } catch (Exception ex) { if (ex instanceof ClassNotFoundException && ex.getMessage() != null && ex.getMessage().contains(scriptName)) { throw new ScriptNotFoundException(scriptName); } } } } private String fixScriptName(String scriptName, List<Resource> allScripts) { try { Set<String> names = new HashSet<String>(); for (Resource script : allScripts) { names.add(script.getFilename().substring(0, script.getFilename().length() - 7)); } List<String> mostSimilar = CosineSimilarity.mostSimilar(scriptName, names); if (mostSimilar.isEmpty()) { return null; } List<String> topMatches = mostSimilar.subList(0, Math.min(5, mostSimilar.size())); return askUserForBestMatch(scriptName, topMatches); } catch (Exception e) { return null; } } private String askUserForBestMatch(String scriptName, List<String> topMatches) { @SuppressWarnings("hiding") GrailsConsole console = GrailsConsole.getInstance(); console.addStatus("Script '" + scriptName + "' not found, did you mean:"); int i = 0; for (String s : topMatches) { console.log(" " + ++i + ") " + s); } int attempts = 0; while (true) { String selection = console.userInput("Please make a selection or enter Q to quit: "); if ("Q".equalsIgnoreCase(selection)) { System.exit(0); } try { int number = Integer.parseInt(selection); if (number > 0 && number <= topMatches.size()) { return topMatches.get(number - 1); } } catch (NumberFormatException ignored) { // ignored } attempts++; if (attempts > 4) { exitWithError("Selection not found.", null); } } } private GantResult executeWithGantInstance(Gant gant, final Closure<?> doNothingClosure) { GantResult result = new GantResult(); result.script = gant.prepareTargets(); gant.setAllPerTargetPostHooks(doNothingClosure); gant.setAllPerTargetPreHooks(doNothingClosure); // Invoke the default target. result.exitCode = gant.executeTargets(); return result; } class GantResult { int exitCode; GroovyObject script; } private boolean isGrailsProject() { return new File(settings.getBaseDir(), "grails-app").exists(); } private boolean isExternalScript(Resource scriptFile) { return scriptsAllowedOutsideOfProject.contains(scriptFile); } private String getScriptNameFromFile(Resource scriptPath) { String scriptFileName = scriptPath .getFilename() .substring(0, scriptPath.getFilename().length() - 7); // trim .groovy extension if (scriptFileName.endsWith("_")) { scriptFileName = scriptFileName.substring(0, scriptFileName.length() - 1); } return scriptFileName; } /** Returns a list of all the executable Gant scripts available to this application. */ public List<Resource> getAvailableScripts() { List<Resource> scripts = new ArrayList<Resource>(); if (settings.getGrailsHome() != null) { addCommandScripts(new File(settings.getGrailsHome(), "scripts"), scripts); } addCommandScripts(new File(settings.getBaseDir(), "scripts"), scripts); addCommandScripts(new File(settings.getUserHome(), ".grails/scripts"), scripts); for (File dir : pluginPathSupport.listKnownPluginDirs()) { addPluginScripts(dir, scripts); } PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(settings.getRootLoader()); try { final Resource[] resources = resolver.getResources("classpath*:META-INF/scripts/*.groovy"); scripts.addAll(Arrays.asList(resources)); } catch (IOException e) { // ignore } return scripts; } /** * Collects all the command scripts provided by the plugin contained in the given directory and * adds them to the given list. */ private static void addPluginScripts(File pluginDir, List<Resource> scripts) { if (!pluginDir.exists()) return; File scriptDir = new File(pluginDir, "scripts"); if (scriptDir.exists()) addCommandScripts(scriptDir, scripts); } /** * Adds all the command scripts (i.e. those whose name does *not* start with an underscore, '_') * found in the given directory to the given list. */ private static void addCommandScripts(File dir, List<Resource> scripts) { if (dir.exists()) { for (File file : dir.listFiles()) { if (scriptFilePattern.matcher(file.getName()).matches()) { scripts.add(new FileSystemResource(file)); } } } } /** * Contains details about a Grails command invocation such as the name of the corresponding * script, the environment (if specified), and the arguments to the command. */ private static class ScriptAndArgs { public String inputName; public String name; public String env; public String args; } }
public static void warning( final SourceUnit sourceUnit, final ASTNode node, final String warningMessage) { final String sample = sourceUnit.getSample(node.getLineNumber(), node.getColumnNumber(), new Janitor()); GrailsConsole.getInstance().warning(warningMessage + "\n\n" + sample); }
// Note: the following only work if you also include _GrailsEvents. public void logError(String message, Throwable t) { GrailsConsole.getInstance().error(message, t); }
/** * Evaluate the arguments to get the name of the script to execute, which environment to run it * in, and the arguments to pass to the script. This also evaluates arguments of the form * "-Dprop=value" and creates system properties from each one. * * @param args Command line arguments */ public static void main(String[] args) { originalIn = System.in; originalOut = System.out; CommandLineParser parser = getCommandLineParser(); GrailsConsole console = GrailsConsole.getInstance(); CommandLine commandLine; try { if (args.length == 0) { commandLine = new DefaultCommandLine(); } else { commandLine = parser.parseString(args[0]); if (commandLine.hasOption(CommandLine.NOANSI_ARGUMENT)) { console.setAnsiEnabled(false); } } } catch (ParseException e) { console.error("Error processing command line arguments: " + e.getMessage()); System.exit(1); return; } String version = System.getProperty("grails.version"); ScriptAndArgs script = processArgumentsAndReturnScriptName(commandLine); // Get hold of the GRAILS_HOME environment variable if it is available. String grailsHome = System.getProperty("grails.home"); // Now we can pick up the Grails version from the Ant project properties. BuildSettings build = null; try { build = new BuildSettings(new File(grailsHome)); build.setModified(commandLine.hasOption(CommandLine.REFRESH_DEPENDENCIES_ARGUMENT)); build.setOffline(commandLine.hasOption(CommandLine.OFFLINE_ARGUMENT)); if (build.getRootLoader() == null) { build.setRootLoader((URLClassLoader) GrailsScriptRunner.class.getClassLoader()); } } catch (Exception e) { exitWithError( "An error occurred loading the grails-app/conf/BuildConfig.groovy file: " + e.getMessage(), null); } // Check that Grails' home actually exists. final File grailsHomeInSettings = build.getGrailsHome(); if (grailsHomeInSettings == null || !grailsHomeInSettings.exists()) { exitWithError("Grails' installation directory not found: " + build.getGrailsHome(), null); } if (commandLine.hasOption(CommandLine.VERSION_ARGUMENT)) { console.log("Grails version: " + build.getGrailsVersion()); System.exit(0); } if (commandLine.hasOption(CommandLine.HELP_ARGUMENT)) { console.log(parser.getHelpMessage()); System.exit(0); } // If there aren't any arguments, then we don't have a command // to execute, so enter "interactive mode" boolean resolveDeps = commandLine.hasOption(CommandLine.REFRESH_DEPENDENCIES_ARGUMENT); if (resolveDeps) { if (commandLine.hasOption("include-source")) { build.setIncludeSource(true); } if (commandLine.hasOption("include-javadoc")) { build.setIncludeJavadoc(true); } } GrailsScriptRunner scriptRunner = new GrailsScriptRunner(build); scriptRunner.setInteractive(!commandLine.hasOption(CommandLine.NON_INTERACTIVE_ARGUMENT)); if ("Interactive".equals(script.name)) { console.error( "The 'interactive' script is deprecated; to run in interactive mode just omit the script name"); script.name = null; } if (script.name == null) { console.updateStatus( "Loading Grails " + (version != null ? version : build.getGrailsVersion())); build.loadConfig(); if (resolveDeps) { ClasspathConfigurer.cleanResolveCache(build); } scriptRunner.initializeState(); try { new InteractiveMode(build, scriptRunner).run(); } catch (Throwable e) { console.error("Interactive mode exited with error: " + e.getMessage(), e); } } else { console.getCategory().push(script.inputName); console.verbose("Base Directory: " + build.getBaseDir().getPath()); try { int exitCode = scriptRunner.executeCommand(commandLine, script.name, script.env); System.exit(exitCode); } catch (ScriptNotFoundException ex) { console.error("Script not found: " + ex.getScriptName()); } catch (Throwable t) { String msg = "Error executing script " + script.name + ": " + t.getMessage(); exitWithError(msg, t); } } }