/* * Copyright 2015-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.jvm.groovy; import static com.google.common.collect.Iterables.any; import static com.google.common.collect.Iterables.transform; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.jvm.java.Javac; import com.facebook.buck.jvm.java.JavacOptions; import com.facebook.buck.jvm.java.OptionsConsumer; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.Tool; import com.facebook.buck.step.ExecutionContext; import com.facebook.buck.step.Step; import com.facebook.buck.step.StepExecutionResult; import com.facebook.buck.util.ProcessExecutor; import com.facebook.buck.util.ProcessExecutorParams; import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSortedSet; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.Optional; class GroovycStep implements Step { private final Tool groovyc; private final Optional<ImmutableList<String>> extraArguments; private final JavacOptions javacOptions; private final SourcePathResolver resolver; private final Path outputDirectory; private final ImmutableSortedSet<Path> sourceFilePaths; private final Path pathToSrcsList; private final ImmutableSortedSet<Path> declaredClasspathEntries; private final ProjectFilesystem filesystem; GroovycStep( Tool groovyc, Optional<ImmutableList<String>> extraArguments, JavacOptions javacOptions, SourcePathResolver resolver, Path outputDirectory, ImmutableSortedSet<Path> sourceFilePaths, Path pathToSrcsList, ImmutableSortedSet<Path> declaredClasspathEntries, ProjectFilesystem filesystem) { this.groovyc = groovyc; this.extraArguments = extraArguments; this.javacOptions = javacOptions; this.resolver = resolver; this.outputDirectory = outputDirectory; this.sourceFilePaths = sourceFilePaths; this.pathToSrcsList = pathToSrcsList; this.declaredClasspathEntries = declaredClasspathEntries; this.filesystem = filesystem; } @Override public StepExecutionResult execute(ExecutionContext context) throws IOException, InterruptedException { try { ProcessExecutorParams params = ProcessExecutorParams.builder() .setCommand(createCommand()) .setEnvironment(context.getEnvironment()) .setDirectory(filesystem.getRootPath().toAbsolutePath()) .build(); writePathToSourcesList(sourceFilePaths); ProcessExecutor processExecutor = context.getProcessExecutor(); return StepExecutionResult.of(processExecutor.launchAndExecute(params)); } catch (IOException e) { e.printStackTrace(context.getStdErr()); return StepExecutionResult.of(-1); } } @Override public String getShortName() { return Joiner.on(" ").join(groovyc.getCommandPrefix(resolver)); } @Override public String getDescription(ExecutionContext context) { return Joiner.on(" ").join(createCommand()); } private ImmutableList<String> createCommand() { final ImmutableList.Builder<String> command = ImmutableList.builder(); command.addAll(groovyc.getCommandPrefix(resolver)); String classpath = Joiner.on(File.pathSeparator).join(transform(declaredClasspathEntries, Object::toString)); command .add("-cp") .add(classpath.isEmpty() ? "''" : classpath) .add("-d") .add(outputDirectory.toString()); addCrossCompilationOptions(command); command.addAll(extraArguments.orElse(ImmutableList.of())); command.add("@" + pathToSrcsList); return command.build(); } private void writePathToSourcesList(Iterable<Path> expandedSources) throws IOException { filesystem.writeLinesToPath( FluentIterable.from(expandedSources) .transform(Object::toString) .transform(Javac.ARGFILES_ESCAPER), pathToSrcsList); } private void addCrossCompilationOptions(final ImmutableList.Builder<String> command) { if (shouldCrossCompile()) { command.add("-j"); javacOptions.appendOptionsTo( new OptionsConsumer() { @Override public void addOptionValue(String option, String value) { // Explicitly disallow the setting of sourcepath in a cross compilation context. // The implementation of `appendOptionsTo` provides a blank default, which // confuses the cross compilation step's javac (it won't find any class files // compiled by groovyc). if (option.equals("sourcepath")) { return; } command.add("-J" + String.format("%s=%s", option, value)); } @Override public void addFlag(String flagName) { command.add("-F" + flagName); } @Override public void addExtras(Collection<String> extras) { for (String extra : extras) { if (extra.startsWith("-")) { addFlag(extra.substring(1)); } else { addFlag(extra); } } } }, resolver, filesystem); } } private boolean shouldCrossCompile() { return any(sourceFilePaths, input -> input.toString().endsWith(".java")); } }