package org.codefx.mvn.jdeps.tool.jdeps; import org.codefx.mvn.jdeps.mojo.MojoLogging; import org.codefx.mvn.jdeps.parse.ViolationParser; import org.codehaus.plexus.util.cli.CommandLineException; import org.codehaus.plexus.util.cli.CommandLineUtils; import org.codehaus.plexus.util.cli.CommandLineUtils.StringStreamConsumer; import org.codehaus.plexus.util.cli.Commandline; import java.io.BufferedReader; import java.io.StringReader; import java.nio.file.Path; import java.util.Objects; import java.util.function.Consumer; import java.util.stream.Stream; import static java.lang.String.format; /** * Executes "jdeps -jdkinternals". */ public class JdkInternalsExecutor { private final Path jDepsExecutable; private final Path pathToCheckedFiles; private final Consumer<String> jDepsOutputConsumer; /** * Creates a new executor. * * @param jDepsExecutable * path to the JDeps executable * @param folderToScan * the path to the folder which jdeps will scan * @param jDepsOutputConsumer * consumer of jdeps' output (line by line) */ public JdkInternalsExecutor(Path jDepsExecutable, Path folderToScan, Consumer<String> jDepsOutputConsumer) { Objects.requireNonNull(jDepsExecutable, "The argument 'jDepsExecutable' must not be null."); Objects.requireNonNull(folderToScan, "The argument 'pathToCheckedFiles' must not be null."); Objects.requireNonNull(jDepsOutputConsumer, "The argument 'jDepsOutputConsumer' must not be null."); this.jDepsExecutable = jDepsExecutable; this.pathToCheckedFiles = folderToScan; this.jDepsOutputConsumer = jDepsOutputConsumer; } // #begin EXECUTE JDEPS /** * Executes jdeps. * * @throws CommandLineException * if running jdeps failed or the tool returned with an error */ public void execute() throws CommandLineException { Commandline jDepsCommand = createJDepsCommand(jDepsExecutable); execute(jDepsCommand); } private Commandline createJDepsCommand(Path jDepsExecutable) { Commandline jDepsCommand = new Commandline(); jDepsCommand.setExecutable(jDepsExecutable.toAbsolutePath().toString()); jDepsCommand.createArg().setValue("-jdkinternals"); jDepsCommand.createArg().setFile(pathToCheckedFiles.toFile()); return jDepsCommand; } private void execute(Commandline jDepsCommand) throws CommandLineException { StringStreamConsumer errorConsoleConsumer = new StringStreamConsumer(); MojoLogging.logger().debug(format("Running JDeps: %s", jDepsCommand)); MojoLogging.logger().debug(String.format( "(JDeps output is forwarded here. " + "Lines are marked: %s = recognized as dependency; %s = not recognized.)", ViolationParser.MESSAGE_MARKER_JDEPS_LINE, ViolationParser.MESSAGE_MARKER_UNKNOWN_LINE)); int exitCode = CommandLineUtils.executeCommandLine( jDepsCommand, jDepsOutputConsumer::accept, errorConsoleConsumer); MojoLogging.logger().debug(format("JDeps completed with exit code %d.", exitCode)); if (exitCode != 0) throwCommandLineException(jDepsCommand, exitCode, errorConsoleConsumer.getOutput()); } private static void throwCommandLineException(Commandline jDepsCommand, int exitCode, String errorOutput) throws CommandLineException { StringBuilder message = new StringBuilder("JDeps returned with exit code '" + exitCode + "'.\n"); message.append("\t Executed command: " + CommandLineUtils.toString(jDepsCommand.getCommandline()).replaceAll("'", "")); message.append("\t Error output:\n"); streamLines(errorOutput).forEachOrdered(errorLine -> message.append("\t\t " + errorLine + "\n")); throw new CommandLineException(message.toString()); } private static Stream<String> streamLines(String lines) { return new BufferedReader(new StringReader(lines)).lines(); } // #end EXECUTE JDEPS }