Exemplo n.º 1
0
 private static void exitWithError(String error, Throwable t) {
   if (t != null) {
     GrailsConsole.getInstance().error(error, t);
   } else {
     GrailsConsole.getInstance().error(error);
   }
   System.exit(1);
 }
Exemplo n.º 2
0
  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);
  }
Exemplo n.º 3
0
  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);
  }
Exemplo n.º 4
0
  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);
      }
    }
  }
Exemplo n.º 5
0
 /**
  * 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"}));
 }
Exemplo n.º 6
0
  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;
  }
Exemplo n.º 7
0
 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);
 }
Exemplo n.º 8
0
  /** 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);
  }
Exemplo n.º 9
0
  /**
   * 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();
    }
  }
 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);
 }
/**
 * 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;
    }
  }
Exemplo n.º 13
0
  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();
  }
  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);
    }
  }
Exemplo n.º 15
0
  /**
   * 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);
      }
    }
  }
Exemplo n.º 16
0
 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);
 }
Exemplo n.º 17
0
/**
 * 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;
  }
}
Exemplo n.º 18
0
 // Note: the following only work if you also include _GrailsEvents.
 public void logError(String message, Throwable t) {
   GrailsConsole.getInstance().error(message, t);
 }