diff -r 28d33fb9097f -r e04318f39f92 langtools/test/tools/lib/toolbox/JavacTask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/lib/toolbox/JavacTask.java Thu Mar 31 15:20:50 2016 -0700 @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package toolbox; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.api.JavacTool; + +/** + * A task to configure and run the Java compiler, javac. + */ +public class JavacTask extends AbstractTask { + private boolean includeStandardOptions; + private List classpath; + private List sourcepath; + private Path outdir; + private List options; + private List classes; + private List files; + private List fileObjects; + private JavaFileManager fileManager; + + private JavaCompiler compiler; + private StandardJavaFileManager internalFileManager; + + /** + * Creates a task to execute {@code javac} using API mode. + * @param toolBox the {@code ToolBox} to use + */ + public JavacTask(ToolBox toolBox) { + super(toolBox, Task.Mode.API); + } + + /** + * Creates a task to execute {@code javac} in a specified mode. + * @param toolBox the {@code ToolBox} to use + * @param mode the mode to be used + */ + public JavacTask(ToolBox toolBox, Task.Mode mode) { + super(toolBox, mode); + } + + /** + * Sets the classpath. + * @param classpath the classpath + * @return this task object + */ + public JavacTask classpath(String classpath) { + this.classpath = Stream.of(classpath.split(File.pathSeparator)) + .filter(s -> !s.isEmpty()) + .map(s -> Paths.get(s)) + .collect(Collectors.toList()); + return this; + } + + /** + * Sets the classpath. + * @param classpath the classpath + * @return this task object + */ + public JavacTask classpath(Path... classpath) { + this.classpath = Arrays.asList(classpath); + return this; + } + + /** + * Sets the sourcepath. + * @param sourcepath the sourcepath + * @return this task object + */ + public JavacTask sourcepath(String sourcepath) { + this.sourcepath = Stream.of(sourcepath.split(File.pathSeparator)) + .filter(s -> !s.isEmpty()) + .map(s -> Paths.get(s)) + .collect(Collectors.toList()); + return this; + } + + /** + * Sets the sourcepath. + * @param sourcepath the sourcepath + * @return this task object + */ + public JavacTask sourcepath(Path... sourcepath) { + this.sourcepath = Arrays.asList(sourcepath); + return this; + } + + /** + * Sets the output directory. + * @param outdir the output directory + * @return this task object + */ + public JavacTask outdir(String outdir) { + this.outdir = Paths.get(outdir); + return this; + } + + /** + * Sets the output directory. + * @param outdir the output directory + * @return this task object + */ + public JavacTask outdir(Path outdir) { + this.outdir = outdir; + return this; + } + + /** + * Sets the options. + * @param options the options + * @return this task object + */ + public JavacTask options(String... options) { + this.options = Arrays.asList(options); + return this; + } + + /** + * Sets the classes to be analyzed. + * @param classes the classes + * @return this task object + */ + public JavacTask classes(String... classes) { + this.classes = Arrays.asList(classes); + return this; + } + + /** + * Sets the files to be compiled or analyzed. + * @param files the files + * @return this task object + */ + public JavacTask files(String... files) { + this.files = Arrays.asList(files); + return this; + } + + /** + * Sets the files to be compiled or analyzed. + * @param files the files + * @return this task object + */ + public JavacTask files(Path... files) { + this.files = Stream.of(files) + .map(Path::toString) + .collect(Collectors.toList()); + return this; + } + + /** + * Sets the sources to be compiled or analyzed. + * Each source string is converted into an in-memory object that + * can be passed directly to the compiler. + * @param sources the sources + * @return this task object + */ + public JavacTask sources(String... sources) { + fileObjects = Stream.of(sources) + .map(s -> new ToolBox.JavaSource(s)) + .collect(Collectors.toList()); + return this; + } + + /** + * Sets the file manager to be used by this task. + * @param fileManager the file manager + * @return this task object + */ + public JavacTask fileManager(JavaFileManager fileManager) { + this.fileManager = fileManager; + return this; + } + + /** + * {@inheritDoc} + * @return the name "javac" + */ + @Override + public String name() { + return "javac"; + } + + /** + * Calls the compiler with the arguments as currently configured. + * @return a Result object indicating the outcome of the compilation + * and the content of any output written to stdout, stderr, or the + * main stream by the compiler. + * @throws TaskError if the outcome of the task is not as expected. + */ + @Override + public Task.Result run() { + if (mode == Task.Mode.EXEC) + return runExec(); + + AbstractTask.WriterOutput direct = new AbstractTask.WriterOutput(); + // The following are to catch output to System.out and System.err, + // in case these are used instead of the primary (main) stream + AbstractTask.StreamOutput sysOut = new AbstractTask.StreamOutput(System.out, System::setOut); + AbstractTask.StreamOutput sysErr = new AbstractTask.StreamOutput(System.err, System::setErr); + int rc; + Map outputMap = new HashMap<>(); + try { + switch (mode == null ? Task.Mode.API : mode) { + case API: + rc = runAPI(direct.pw); + break; + case CMDLINE: + rc = runCommand(direct.pw); + break; + default: + throw new IllegalStateException(); + } + } catch (IOException e) { + toolBox.out.println("Exception occurred: " + e); + rc = 99; + } finally { + outputMap.put(Task.OutputKind.STDOUT, sysOut.close()); + outputMap.put(Task.OutputKind.STDERR, sysErr.close()); + outputMap.put(Task.OutputKind.DIRECT, direct.close()); + } + return checkExit(new Task.Result(toolBox, this, rc, outputMap)); + } + + private int runAPI(PrintWriter pw) throws IOException { + try { +// if (compiler == null) { + // TODO: allow this to be set externally +// compiler = ToolProvider.getSystemJavaCompiler(); + compiler = JavacTool.create(); +// } + + if (fileManager == null) + fileManager = internalFileManager = compiler.getStandardFileManager(null, null, null); + if (outdir != null) + setLocationFromPaths(StandardLocation.CLASS_OUTPUT, Collections.singletonList(outdir)); + if (classpath != null) + setLocationFromPaths(StandardLocation.CLASS_PATH, classpath); + if (sourcepath != null) + setLocationFromPaths(StandardLocation.SOURCE_PATH, sourcepath); + List allOpts = new ArrayList<>(); + if (options != null) + allOpts.addAll(options); + + Iterable allFiles = joinFiles(files, fileObjects); + JavaCompiler.CompilationTask task = compiler.getTask(pw, + fileManager, + null, // diagnostic listener; should optionally collect diags + allOpts, + classes, + allFiles); + return ((JavacTaskImpl) task).doCall().exitCode; + } finally { + if (internalFileManager != null) + internalFileManager.close(); + } + } + + private void setLocationFromPaths(StandardLocation location, List files) throws IOException { + if (!(fileManager instanceof StandardJavaFileManager)) + throw new IllegalStateException("not a StandardJavaFileManager"); + ((StandardJavaFileManager) fileManager).setLocationFromPaths(location, files); + } + + private int runCommand(PrintWriter pw) { + List args = getAllArgs(); + String[] argsArray = args.toArray(new String[args.size()]); + return com.sun.tools.javac.Main.compile(argsArray, pw); + } + + private Task.Result runExec() { + List args = new ArrayList<>(); + Path javac = toolBox.getJDKTool("javac"); + args.add(javac.toString()); + if (includeStandardOptions) { + args.addAll(toolBox.split(System.getProperty("test.tool.vm.opts"), " +")); + args.addAll(toolBox.split(System.getProperty("test.compiler.opts"), " +")); + } + args.addAll(getAllArgs()); + + String[] argsArray = args.toArray(new String[args.size()]); + ProcessBuilder pb = getProcessBuilder(); + pb.command(argsArray); + try { + return runProcess(toolBox, this, pb.start()); + } catch (IOException | InterruptedException e) { + throw new Error(e); + } + } + + private List getAllArgs() { + List args = new ArrayList<>(); + if (options != null) + args.addAll(options); + if (outdir != null) { + args.add("-d"); + args.add(outdir.toString()); + } + if (classpath != null) { + args.add("-classpath"); + args.add(toSearchPath(classpath)); + } + if (sourcepath != null) { + args.add("-sourcepath"); + args.add(toSearchPath(sourcepath)); + } + if (classes != null) + args.addAll(classes); + if (files != null) + args.addAll(files); + + return args; + } + + private String toSearchPath(List files) { + return files.stream() + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + } + + private Iterable joinFiles( + List files, List fileObjects) { + if (files == null) + return fileObjects; + if (internalFileManager == null) + internalFileManager = compiler.getStandardFileManager(null, null, null); + Iterable filesAsFileObjects = + internalFileManager.getJavaFileObjectsFromStrings(files); + if (fileObjects == null) + return filesAsFileObjects; + List combinedList = new ArrayList<>(); + for (JavaFileObject o : filesAsFileObjects) + combinedList.add(o); + combinedList.addAll(fileObjects); + return combinedList; + } +}