Java tutorial
/* * Copyright 2012-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package com.facebook.buck.java; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.RuleKeyBuilder; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.step.ExecutionContext; import com.facebook.buck.util.Ansi; import com.facebook.buck.util.Console; import com.facebook.buck.util.HumanReadableException; import com.facebook.buck.util.ProcessExecutor; import com.facebook.buck.util.ProcessExecutorParams; import com.facebook.buck.util.Verbosity; import com.facebook.buck.zip.Unzip; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Functions; import com.google.common.base.Joiner; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.file.Path; import java.util.Map; public class ExternalJavac implements Javac { private static final JavacVersion DEFAULT_VERSION = JavacVersion.of("unknown version"); private final Path pathToJavac; private final Supplier<JavacVersion> version; public ExternalJavac(final Path pathToJavac) { this.pathToJavac = pathToJavac; this.version = Suppliers.memoize(new Supplier<JavacVersion>() { @Override public JavacVersion get() { ProcessExecutorParams params = ProcessExecutorParams.builder() .setCommand(ImmutableList.of(pathToJavac.toString(), "-version")).build(); ProcessExecutor.Result result; try (PrintStream stdout = new PrintStream(new ByteArrayOutputStream()); PrintStream stderr = new PrintStream(new ByteArrayOutputStream())) { result = createProcessExecutor(stdout, stderr).launchAndExecute(params); } catch (InterruptedException | IOException e) { throw new RuntimeException(e); } Optional<String> stderr = result.getStderr(); String output = stderr.or("").trim(); if (Strings.isNullOrEmpty(output)) { return DEFAULT_VERSION; } else { return JavacVersion.of(output); } } }); } @Override public ImmutableCollection<BuildRule> getDeps(SourcePathResolver resolver) { return ImmutableSortedSet.of(); } @Override public ImmutableCollection<SourcePath> getInputs() { return ImmutableSortedSet.of(); } @Override public ImmutableList<String> getCommandPrefix(SourcePathResolver resolver) { return ImmutableList.<String>builder().add(pathToJavac.toString()).build(); } public static Javac createJavac(Path pathToJavac) { return new ExternalJavac(pathToJavac); } @Override public JavacVersion getVersion() { return version.get(); } @VisibleForTesting ProcessExecutor createProcessExecutor(PrintStream stdout, PrintStream stderr) { return new ProcessExecutor(new Console(Verbosity.SILENT, stdout, stderr, Ansi.withoutTty())); } @Override public String getDescription(ImmutableList<String> options, ImmutableSet<Path> javaSourceFilePaths, Optional<Path> pathToSrcsList) { StringBuilder builder = new StringBuilder(pathToJavac.toString()); builder.append(" "); Joiner.on(" ").appendTo(builder, options); builder.append(" "); if (pathToSrcsList.isPresent()) { builder.append("@").append(pathToSrcsList.get()); } else { Joiner.on(" ").appendTo(builder, javaSourceFilePaths); } return builder.toString(); } @Override public String getShortName() { return pathToJavac.toString(); } @Override public RuleKeyBuilder appendToRuleKey(RuleKeyBuilder builder) { if (DEFAULT_VERSION.equals(getVersion())) { return builder.setReflectively("javac", pathToJavac); } return builder.setReflectively("javac.version", getVersion().toString()); } public Path getPath() { return pathToJavac; } @Override public int buildWithClasspath(ExecutionContext context, ProjectFilesystem filesystem, SourcePathResolver resolver, BuildTarget invokingRule, ImmutableList<String> options, ImmutableSet<Path> javaSourceFilePaths, Optional<Path> pathToSrcsList, Optional<Path> workingDirectory) throws InterruptedException { ImmutableList.Builder<String> command = ImmutableList.builder(); command.add(pathToJavac.toString()); command.addAll(options); ImmutableList<Path> expandedSources; try { expandedSources = getExpandedSourcePaths(filesystem, invokingRule, javaSourceFilePaths, workingDirectory); } catch (IOException e) { throw new HumanReadableException("Unable to expand sources for %s into %s", invokingRule, workingDirectory); } if (pathToSrcsList.isPresent()) { try { filesystem.writeLinesToPath(FluentIterable.from(expandedSources) .transform(Functions.toStringFunction()).transform(ARGFILES_ESCAPER), pathToSrcsList.get()); command.add("@" + pathToSrcsList.get()); } catch (IOException e) { context.logError(e, "Cannot write list of .java files to compile to %s file! Terminating compilation.", pathToSrcsList.get()); return 1; } } else { for (Path source : expandedSources) { command.add(source.toString()); } } ProcessBuilder processBuilder = new ProcessBuilder(command.build()); // Set environment to client environment and add additional information. Map<String, String> env = processBuilder.environment(); env.clear(); env.putAll(context.getEnvironment()); env.put("BUCK_INVOKING_RULE", invokingRule.toString()); env.put("BUCK_TARGET", invokingRule.toString()); env.put("BUCK_DIRECTORY_ROOT", filesystem.getRootPath().toAbsolutePath().toString()); processBuilder.directory(filesystem.getRootPath().toAbsolutePath().toFile()); // Run the command int exitCode = -1; try { ProcessExecutor.Result result = context.getProcessExecutor().execute(processBuilder.start()); exitCode = result.getExitCode(); } catch (IOException e) { e.printStackTrace(context.getStdErr()); return exitCode; } return exitCode; } private ImmutableList<Path> getExpandedSourcePaths(ProjectFilesystem projectFilesystem, BuildTarget invokingRule, ImmutableSet<Path> javaSourceFilePaths, Optional<Path> workingDirectory) throws IOException { // Add sources file or sources list to command ImmutableList.Builder<Path> sources = ImmutableList.builder(); for (Path path : javaSourceFilePaths) { String pathString = path.toString(); if (pathString.endsWith(".java")) { sources.add(path); } else if (pathString.endsWith(SRC_ZIP) || pathString.endsWith(SRC_JAR)) { if (!workingDirectory.isPresent()) { throw new HumanReadableException( "Attempting to compile target %s which specified a .src.zip input %s but no " + "working directory was specified.", invokingRule.toString(), path); } // For a Zip of .java files, create a JavaFileObject for each .java entry. ImmutableList<Path> zipPaths = Unzip.extractZipFile(projectFilesystem.resolve(path), projectFilesystem.resolve(workingDirectory.get()), Unzip.ExistingFileMode.OVERWRITE); sources.addAll(FluentIterable.from(zipPaths).filter(new Predicate<Path>() { @Override public boolean apply(Path input) { return input.toString().endsWith(".java"); } })); } } return sources.build(); } }