Пример #1
0
  /**
   * This method is the main manager of the linking process. It should only be run if an "outfile"
   * has been provided in the configuration. It will attempt to link all the files in the objdir
   * into a simple executable/library.
   */
  private void link() {
    // generate the command line
    Commandline commandline = generateLinkCommand();

    // create the execution object
    Execute runner =
        new Execute(
            new LogStreamHandler(configuration.getTask(), Project.MSG_INFO, Project.MSG_WARN));

    runner.setCommandline(commandline.getCommandline());

    // run the command
    try {
      task.log("Starting Link ");
      task.log(commandline.toString(), Project.MSG_DEBUG);

      int exitValue = runner.execute();
      if (exitValue != 0) throw new BuildException("Link Failed, (exit value: " + exitValue + ")");
    } catch (IOException e) {
      String msg =
          "There was a problem running the linker, this usually occurs when the "
              + "linker can't be found, make sure it is on your path. full error: "
              + e.getMessage();
      throw new BuildException(msg, e);
    }

    task.log("Link complete. Library in directory: " + configuration.getOutputDirectory());
    task.log(""); // a little bit of space
  }
Пример #2
0
  protected Flags runDiff(
      SourceFile vmFile, SourceFile cpFile, String diffFileName, Map<String, String> packageDiffs)
      throws IOException, InterruptedException {
    final String[] cmd = {
      "diff",
      "-b", // Ignore white space change
      // "-E", // Ignore changes due to tab expansion
      // "-w", // Ignore all white space change
      // "-B", // Ignore changes whose lines are all blank
      // "-N", // Treat absent files as empty
      "-au",
      "-I",
      ".*$" + "Id:.*$.*", // Avoid cvs keyword
      // expansion in this string
      vmFile.getFileName(),
      cpFile.getFile().getAbsolutePath()
    };
    final ByteArrayOutputStream out = new ByteArrayOutputStream();
    final ByteArrayOutputStream err = new ByteArrayOutputStream();
    final PumpStreamHandler streamHandler = new PumpStreamHandler(out, err);
    final Execute exe = new Execute(streamHandler);
    exe.setCommandline(cmd);
    exe.setWorkingDirectory(vmFile.getBaseDir());
    final int rc = exe.execute();
    if ((rc != 0) && (out.size() > 0)) {
      File diffFile = new File(destDir, diffFileName);
      FileOutputStream os = new FileOutputStream(diffFile);
      try {
        final byte[] diff = out.toByteArray();
        os.write(diff);
        os.flush();

        final String diffStr = new String(diff);
        final String pkg = vmFile.getPackageName();
        String pkgDiff;
        if (packageDiffs.containsKey(pkg)) {
          pkgDiff = packageDiffs.get(pkg);
          pkgDiff = pkgDiff + "diff\n" + diffStr;
        } else {
          pkgDiff = diffStr;
        }
        packageDiffs.put(pkg, pkgDiff);

        Flags flags = getFlags(diffStr);
        if (!vmFile.getTarget().equals(cpFile.getTarget())) {
          flags.set(FLAG_TARGET_DIFF);
        }
        flags.set(NEEDS_MERGE);
        return flags;
      } finally {
        os.close();
      }
    } else {
      return new Flags(NO_CHANGE);
    }
  }
Пример #3
0
 private int run(String[] command) throws BuildException {
   Execute exe = new Execute(new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN), null);
   exe.setAntRun(project);
   exe.setWorkingDirectory(dir);
   exe.setCommandline(command);
   try {
     return exe.execute();
   } catch (IOException e) {
     throw new BuildException(e, location);
   }
 }
  public String execute(String[] commandLine, File sourceCodeDirectory) throws IOException {
    StringOutputStream stringOutputStream = new StringOutputStream();

    Execute execute = new Execute(new PumpStreamHandler(stringOutputStream));
    execute.setWorkingDirectory(sourceCodeDirectory);
    execute.setCommandline(commandLine);
    execute.execute();

    String output = stringOutputStream.toString();
    stringOutputStream.close();
    return output;
  }
Пример #5
0
    public void run() {
      Commandline theCommand;
      // get the name of the output file
      File ofile = helper.getOFile(objectDirectory, sourceFile);
      if (sourceFile.getName().endsWith(".rc")) {
        // Is this a win32 resource file?
        // create the full command
        theCommand = new Commandline();
        theCommand.setExecutable("windres");
        theCommand.createArgument().setValue("-i");
        theCommand.createArgument().setFile(sourceFile);
        theCommand.createArgument().setValue("-J");
        theCommand.createArgument().setValue("rc");
        theCommand.createArgument().setValue("-o");
        theCommand.createArgument().setFile(ofile);
        theCommand.createArgument().setValue("-O");
        theCommand.createArgument().setValue("coff");
      } else {
        // create the full command
        theCommand = (Commandline) command.clone();
        theCommand.createArgument().setFile(sourceFile);
        theCommand.createArgument().setValue("-o");
        theCommand.createArgument().setFile(ofile);
      }

      // create the execution object
      Execute runner =
          new Execute(
              new LogStreamHandler(configuration.getTask(), Project.MSG_INFO, Project.MSG_WARN));

      // runner.setAntRun( project );
      runner.setCommandline(theCommand.getCommandline());

      // run the command
      try {
        task.log("  " + sourceFile.getName());
        task.log(theCommand.toString(), Project.MSG_DEBUG);
        int exitValue = runner.execute();
        if (exitValue != 0) {
          throw new BuildException("Compile Failed, (exit value: " + exitValue + ")");
        }
      } catch (IOException e) {
        String msg =
            "There was a problem running the compiler, this usually occurs when "
                + "it can't be found, make sure it is on your path. full error: "
                + e.getMessage();
        throw new BuildException(msg, e);
      }
    }
Пример #6
0
  /**
   * Executes the task.
   *
   * <p>Builds a command line to execute cleartool and then calls Exec's run method to execute the
   * command line.
   *
   * @throws BuildException if the command fails and failonerr is set to true
   */
  public void execute() throws BuildException {
    Commandline commandLine = new Commandline();
    Project aProj = getProject();
    int result = 0;

    // Default the viewpath to basedir if it is not specified
    if (getViewPath() == null) {
      setViewPath(aProj.getBaseDir().getPath());
    }

    // build the command line from what we got the format is
    // cleartool lock [options...]
    // as specified in the CLEARTOOL.EXE help
    commandLine.setExecutable(getClearToolCommand());
    commandLine.createArgument().setValue(COMMAND_UNLOCK);

    // Check the command line options
    checkOptions(commandLine);

    // For debugging
    // System.out.println(commandLine.toString());

    if (!getFailOnErr()) {
      getProject().log("Ignoring any errors that occur for: " + getOpType(), Project.MSG_VERBOSE);
    }
    result = run(commandLine);
    if (Execute.isFailure(result) && getFailOnErr()) {
      String msg = "Failed executing: " + commandLine.toString();
      throw new BuildException(msg, getLocation());
    }
  }
Пример #7
0
  /**
   * Executes the task.
   *
   * <p>Builds a command line to execute cleartool and then calls Exec's run method to execute the
   * command line.
   */
  public void execute() throws BuildException {
    Commandline commandLine = new Commandline();
    Project aProj = getProject();
    int result = 0;

    // Check for required attributes
    if (getTypeName() == null) {
      throw new BuildException("Required attribute TypeName not specified");
    }

    // Default the viewpath to basedir if it is not specified
    if (getViewPath() == null) {
      setViewPath(aProj.getBaseDir().getPath());
    }

    // build the command line from what we got. the format is
    // cleartool mklabel [options...] [viewpath ...]
    // as specified in the CLEARTOOL help
    commandLine.setExecutable(getClearToolCommand());
    commandLine.createArgument().setValue(COMMAND_MKLABEL);

    checkOptions(commandLine);

    result = run(commandLine);
    if (Execute.isFailure(result)) {
      String msg = "Failed executing: " + commandLine.toString();
      throw new BuildException(msg, location);
    }
  }
  /**
   * Executes the task.
   *
   * <p>Builds a command line to execute ccm and then calls Exec's run method to execute the command
   * line.
   *
   * @throws BuildException on error
   */
  public void execute() throws BuildException {
    Commandline commandLine = new Commandline();
    int result = 0;

    // build the command line from what we got the format
    // as specified in the CCM.EXE help
    commandLine.setExecutable(getCcmCommand());
    commandLine.createArgument().setValue(getCcmAction());

    checkOptions(commandLine);

    result = run(commandLine, this);
    if (Execute.isFailure(result)) {
      String msg = "Failed executing: " + commandLine.toString();
      throw new BuildException(msg, getLocation());
    }

    // create task ok, set this task as the default one
    Commandline commandLine2 = new Commandline();
    commandLine2.setExecutable(getCcmCommand());
    commandLine2.createArgument().setValue(COMMAND_DEFAULT_TASK);
    commandLine2.createArgument().setValue(getTask());

    log(commandLine.describeCommand(), Project.MSG_DEBUG);

    result = run(commandLine2);
    if (result != 0) {
      String msg = "Failed executing: " + commandLine2.toString();
      throw new BuildException(msg, getLocation());
    }
  }
Пример #9
0
  /**
   * Executes the task.
   *
   * <p>Builds a command line to execute cleartool and then calls Exec's run method to execute the
   * command line.
   *
   * @throws BuildException if the command fails and failonerr is set to true
   */
  public void execute() throws BuildException {
    Commandline commandLine = new Commandline();
    int result = 0;

    // Check for required attributes
    if (getTypeKind() == null) {
      throw new BuildException("Required attribute TypeKind not specified");
    }
    if (getTypeName() == null) {
      throw new BuildException("Required attribute TypeName not specified");
    }

    // build the command line from what we got. the format is
    // cleartool rmtype [options...] type-selector...
    // as specified in the CLEARTOOL help
    commandLine.setExecutable(getClearToolCommand());
    commandLine.createArgument().setValue(COMMAND_RMTYPE);

    checkOptions(commandLine);

    if (!getFailOnErr()) {
      getProject()
          .log("Ignoring any errors that occur for: " + getTypeSpecifier(), Project.MSG_VERBOSE);
    }
    result = run(commandLine);
    if (Execute.isFailure(result) && getFailOnErr()) {
      String msg = "Failed executing: " + commandLine.toString();
      throw new BuildException(msg, getLocation());
    }
  }
Пример #10
0
  private int executeRunnerClassAsForked() throws BuildException {
    CommandlineJava cmd = initializeJavaCommand();

    Execute execute = new Execute(new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN));
    execute.setCommandline(cmd.getCommandline());
    execute.setNewenvironment(false);
    execute.setAntRun(getProject());

    log(cmd.describeCommand(), Project.MSG_VERBOSE);
    int retVal;
    try {
      retVal = execute.execute();
    } catch (IOException e) {
      throw new BuildException("Process fork failed.", e, getLocation());
    }

    return retVal;
  }
Пример #11
0
 /** execute in a forked VM */
 private int run(String[] command) throws BuildException {
   PumpStreamHandler psh =
       new PumpStreamHandler(
           new LogOutputStream(this, Project.MSG_INFO),
           new TeeOutputStream(new LogOutputStream(this, Project.MSG_WARN), bos));
   Execute exe = new Execute(psh, null);
   exe.setAntRun(getProject());
   if (workingdir != null) {
     exe.setWorkingDirectory(workingdir);
   }
   exe.setCommandline(command);
   try {
     return exe.execute();
   } catch (IOException e) {
     throw new BuildException(e, getLocation());
   } finally {
     FileUtils.close(bos);
   }
 }
Пример #12
0
 private void runForked(String[] commandLine) {
   // use the main method in FileSystemCompiler
   final Execute executor =
       new Execute(); // new LogStreamHandler ( attributes , Project.MSG_INFO , Project.MSG_WARN )
                      // ) ;
   executor.setAntRun(getProject());
   executor.setWorkingDirectory(getProject().getBaseDir());
   executor.setCommandline(commandLine);
   try {
     executor.execute();
   } catch (final IOException ioe) {
     throw new BuildException("Error running forked groovyc.", ioe);
   }
   final int returnCode = executor.getExitValue();
   if (returnCode != 0) {
     taskSuccess = false;
     if (errorProperty != null) {
       getProject().setNewProperty(errorProperty, "true");
     }
     if (failOnError) {
       throw new BuildException("Forked groovyc returned error code: " + returnCode);
     } else {
       log.error("Forked groovyc returned error code: " + returnCode);
     }
   }
 }
Пример #13
0
  /**
   * Combine process environment variables and command's environment to emulate the default behavior
   * of the Execute task. Needed especially when user expects environment to be available to custom
   * command (e.g. - xvnc with player not on path).
   */
  @SuppressWarnings("unchecked")
  private String[] getJointEnvironment() {
    Vector procEnvironment = Execute.getProcEnvironment();
    String[] environment =
        new String[procEnvironment.size() + proxiedCommand.getEnvironment().length];
    System.arraycopy(procEnvironment.toArray(), 0, environment, 0, procEnvironment.size());
    System.arraycopy(
        proxiedCommand.getEnvironment(),
        0,
        environment,
        procEnvironment.size(),
        proxiedCommand.getEnvironment().length);

    return environment;
  }
Пример #14
0
 private void executeCommand(Commandline command) {
   try {
     Execute exe;
     if (this.xml != null) {
       String xml = getProject().replaceProperties(this.xml);
       InputStream bis = new ByteArrayInputStream(xml.getBytes());
       ExecuteStreamHandler sh = new PumpStreamHandler(System.out, System.err, bis);
       exe = new Execute(sh);
     } else {
       exe = new Execute();
     }
     exe.setAntRun(getProject());
     exe.setWorkingDirectory(getProject().getBaseDir());
     exe.setCommandline(command.getCommandline());
     log(command.toString());
     int r = exe.execute();
     if (r < 0) {
       throw new BuildException("Processing error!", getLocation());
     }
   } catch (IOException e) {
     throw new BuildException(
         "Error running " + command.getCommandline()[0] + " compiler.", e, getLocation());
   }
 }
 /**
  * load the environment values
  *
  * @param prefix prefix to place before them
  * @param xmlProp
  * @param file
  */
 protected void loadEnvironment(String prefix, IXMLElement xmlProp, File file)
     throws CompilerException {
   Properties props = new Properties();
   packagerListener.packagerMsg("Loading Environment " + prefix, PackagerListener.MSG_VERBOSE);
   Vector osEnv = Execute.getProcEnvironment();
   for (Enumeration e = osEnv.elements(); e.hasMoreElements(); ) {
     String entry = (String) e.nextElement();
     int pos = entry.indexOf('=');
     if (pos == -1) {
       packagerListener.packagerMsg("Ignoring " + prefix, PackagerListener.MSG_WARN);
     } else {
       props.put(prefix + entry.substring(0, pos), entry.substring(pos + 1));
     }
   }
   addProperties(props, xmlProp, file, prefix);
 }
Пример #16
0
  /**
   * Executes the task.
   *
   * <p>Builds a command line to execute ccm and then calls Exec's run method to execute the command
   * line.
   */
  public void execute() throws BuildException {
    Commandline commandLine = new Commandline();
    int result = 0;

    // build the command line from what we got the format
    // as specified in the CCM.EXE help
    commandLine.setExecutable(getCcmCommand());
    commandLine.createArgument().setValue(getCcmAction());

    checkOptions(commandLine);

    result = run(commandLine);
    if (Execute.isFailure(result)) {
      String msg = "Failed executing: " + commandLine.toString();
      throw new BuildException(msg, getLocation());
    }
  }
Пример #17
0
  public void execute() throws BuildException {
    validateAttributes();

    // TODO: use ANTLR to parse the grammer file to do this.
    if (target.lastModified() > getGeneratedFile().lastModified()) {
      commandline.createArgument().setValue("-o");
      commandline.createArgument().setValue(outputDirectory.toString());
      commandline.createArgument().setValue(target.toString());

      if (fork) {
        log("Forking " + commandline.toString(), Project.MSG_VERBOSE);
        int err = run(commandline.getCommandline());
        if (err == 1) {
          throw new BuildException("ANTLR returned: " + err, location);
        }
      } else {
        Execute.runCommand(this, commandline.getCommandline());
      }
    }
  }
Пример #18
0
  /**
   * execute this task.
   *
   * @throws BuildException on error.
   */
  public void execute() throws BuildException {

    checkConfiguration();

    Vector files = getFileList();

    // quick exit if the target is up to date
    if (isUpToDate(files)) {
      return;
    }

    log("Building " + archiveType + ": " + cabFile.getAbsolutePath());

    if (!Os.isFamily("windows")) {
      log("Using listcab/libcabinet", Project.MSG_VERBOSE);

      StringBuffer sb = new StringBuffer();

      Enumeration fileEnum = files.elements();

      while (fileEnum.hasMoreElements()) {
        sb.append(fileEnum.nextElement()).append("\n");
      }
      sb.append("\n").append(cabFile.getAbsolutePath()).append("\n");

      try {
        Process p =
            Execute.launch(
                getProject(),
                new String[] {"listcab"},
                null,
                baseDir != null ? baseDir : getProject().getBaseDir(),
                true);
        OutputStream out = p.getOutputStream();

        // Create the stream pumpers to forward listcab's stdout and stderr to the log
        // note: listcab is an interactive program, and issues prompts for every new line.
        //       Therefore, make it show only with verbose logging turned on.
        LogOutputStream outLog = new LogOutputStream(this, Project.MSG_VERBOSE);
        LogOutputStream errLog = new LogOutputStream(this, Project.MSG_ERR);
        StreamPumper outPump = new StreamPumper(p.getInputStream(), outLog);
        StreamPumper errPump = new StreamPumper(p.getErrorStream(), errLog);

        // Pump streams asynchronously
        (new Thread(outPump)).start();
        (new Thread(errPump)).start();

        out.write(sb.toString().getBytes());
        out.flush();
        out.close();

        // A wild default for when the thread is interrupted
        int result = DEFAULT_RESULT;

        try {
          // Wait for the process to finish
          result = p.waitFor();

          // Wait for the end of output and error streams
          outPump.waitFor();
          outLog.close();
          errPump.waitFor();
          errLog.close();
        } catch (InterruptedException ie) {
          log("Thread interrupted: " + ie);
        }

        // Informative summary message in case of errors
        if (Execute.isFailure(result)) {
          log("Error executing listcab; error code: " + result);
        }
      } catch (IOException ex) {
        String msg = "Problem creating " + cabFile + " " + ex.getMessage();
        throw new BuildException(msg, getLocation());
      }
    } else {
      try {
        File listFile = createListFile(files);
        ExecTask exec = createExec();
        File outFile = null;

        // die if cabarc fails
        exec.setFailonerror(true);
        exec.setDir(baseDir);

        if (!doVerbose) {
          outFile = FILE_UTILS.createTempFile("ant", "", null, true, true);
          exec.setOutput(outFile);
        }

        exec.setExecutable("cabarc");
        exec.createArg().setValue("-r");
        exec.createArg().setValue("-p");

        if (!doCompress) {
          exec.createArg().setValue("-m");
          exec.createArg().setValue("none");
        }

        if (cmdOptions != null) {
          exec.createArg().setLine(cmdOptions);
        }

        exec.createArg().setValue("n");
        exec.createArg().setFile(cabFile);
        exec.createArg().setValue("@" + listFile.getAbsolutePath());

        exec.execute();

        if (outFile != null) {
          outFile.delete();
        }

        listFile.delete();
      } catch (IOException ioe) {
        String msg = "Problem creating " + cabFile + " " + ioe.getMessage();
        throw new BuildException(msg, getLocation());
      }
    }
  }
Пример #19
0
  @Override
  public void execute() throws BuildException {

    // Source directory defaults to current directory
    if (_sourceDir == null) {
      _sourceDir = getProject().getBaseDir();
    }

    // Destination directory defaults to source directory
    if (_destDir == null) {
      _destDir = _sourceDir;
    }

    // Check the directories
    checkDir("Source directory", _sourceDir, true, false);
    checkDir("Destination directory", _destDir, false, true);

    // Create a watch dog, if there is a time-out configured
    ExecuteWatchdog watchdog = (_timeOut > 0L) ? new ExecuteWatchdog(_timeOut) : null;

    // Determine what command to execute
    String command = (_command == null || _command.length() < 1) ? DEFAULT_COMMAND : _command;

    // Check that the command is executable
    Buffer buffer = new Buffer();
    Execute execute = new Execute(buffer, watchdog);
    String[] cmdline = new String[] {command, "-v"};
    execute.setAntRun(getProject());
    execute.setCommandline(cmdline);
    try {
      if (execute.execute() != 0) {
        throw new BuildException(
            "Unable to execute LessCSS command "
                + quote(command)
                + ". Running '"
                + command
                + " -v' resulted in exit code "
                + execute.getExitValue()
                + '.');
      }
    } catch (IOException cause) {
      throw new BuildException("Unable to execute LessCSS command " + quote(command) + '.', cause);
    }

    // Display the command and version number
    String versionString = buffer.getOutString().trim();
    if (versionString.startsWith(command)) {
      versionString = versionString.substring(command.length()).trim();
    }
    if (versionString.startsWith("v")) {
      versionString = versionString.substring(1).trim();
    }
    log(
        "Using command " + quote(command) + ", version is " + quote(versionString) + '.',
        MSG_VERBOSE);

    // TODO: Improve this, detect kind of command
    boolean createOutputFile = command.indexOf("plessc") >= 0;

    // Preparations done, consider each individual file for processing
    log(
        "Transforming from " + _sourceDir.getPath() + " to " + _destDir.getPath() + '.',
        MSG_VERBOSE);
    long start = System.currentTimeMillis();
    int failedCount = 0, successCount = 0, skippedCount = 0;
    for (String inFileName : getDirectoryScanner(_sourceDir).getIncludedFiles()) {

      // Make sure the input file exists
      File inFile = new File(_sourceDir, inFileName);
      if (!inFile.exists()) {
        continue;
      }

      // Determine if the file type is supported
      if (!matches(inFileName.toLowerCase(), "\\.less$")) {
        log(
            "Skipping "
                + quote(inFileName)
                + " because the file does not end in \".less\" (case-insensitive).",
            MSG_VERBOSE);
        skippedCount++;
        continue;
      }

      // Some preparations related to the input file and output file
      long thisStart = System.currentTimeMillis();
      String outFileName = inFile.getName().replaceFirst("\\.less$", ".css");
      File outFile = new File(_destDir, outFileName);
      String outFilePath = outFile.getPath();
      String inFilePath = inFile.getPath();

      if (!_overwrite) {

        // Skip this file is the output file exists and is newer
        if (outFile.exists() && (outFile.lastModified() > inFile.lastModified())) {
          log("Skipping " + quote(inFileName) + " because output file is newer.", MSG_VERBOSE);
          skippedCount++;
          continue;
        }
      }

      // Prepare for the command execution
      buffer = new Buffer();
      watchdog = (_timeOut > 0L) ? new ExecuteWatchdog(_timeOut) : null;
      execute = new Execute(buffer, watchdog);
      cmdline =
          createOutputFile
              ? new String[] {command, inFilePath}
              : new String[] {command, inFilePath, outFilePath};

      execute.setAntRun(getProject());
      execute.setCommandline(cmdline);

      // Execute the command
      boolean failure;
      try {
        execute.execute();
        failure = execute.isFailure();
      } catch (IOException cause) {
        failure = true;
      }

      // Output to stderr or stdout indicates a failure
      String errorOutput = buffer.getErrString();
      errorOutput = isEmpty(errorOutput) ? buffer.getOutString() : errorOutput;
      failure = failure ? true : !isEmpty(errorOutput);

      // Create the output file if the command just sent everything to
      // standard out
      if (createOutputFile) {
        try {
          buffer.writeOutTo(new FileOutputStream(outFile));
        } catch (IOException cause) {
          throw new BuildException(
              "Failed to write output to file \"" + outFile.getPath() + "\".", cause);
        }
      }

      // Log the result for this individual file
      long thisDuration = System.currentTimeMillis() - thisStart;
      if (failure) {
        String logMessage = "Failed to transform " + quote(inFilePath);
        if (isEmpty(errorOutput)) {
          logMessage += '.';
        } else {
          logMessage += ':' + System.getProperty("line.separator") + errorOutput;
        }
        log(logMessage, MSG_ERR);
        failedCount++;
      } else {
        log("Transformed " + quote(inFileName) + " in " + thisDuration + " ms.", MSG_VERBOSE);
        successCount++;
      }
    }

    // Log the total result
    long duration = System.currentTimeMillis() - start;
    if (failedCount > 0) {
      throw new BuildException(
          ""
              + failedCount
              + " file(s) failed to transform, while "
              + successCount
              + " succeeded. Total duration is "
              + duration
              + " ms.");
    } else {
      log(
          ""
              + successCount
              + " file(s) transformed in "
              + duration
              + " ms; "
              + skippedCount
              + " file(s) skipped.");
    }
  }