/* * 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.shell; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.MacroException; import com.facebook.buck.parser.NoSuchBuildTargetException; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.CellPathResolver; import com.facebook.buck.rules.CommonDescriptionArg; import com.facebook.buck.rules.Description; import com.facebook.buck.rules.HasTests; import com.facebook.buck.rules.ImplicitDepsInferringDescription; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathRuleFinder; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.args.MacroArg; import com.facebook.buck.rules.macros.ClasspathMacroExpander; import com.facebook.buck.rules.macros.ExecutableMacroExpander; import com.facebook.buck.rules.macros.LocationMacroExpander; import com.facebook.buck.rules.macros.MacroExpander; import com.facebook.buck.rules.macros.MacroHandler; import com.facebook.buck.rules.macros.MavenCoordinatesMacroExpander; import com.facebook.buck.rules.macros.QueryOutputsMacroExpander; import com.facebook.buck.rules.macros.QueryTargetsMacroExpander; import com.facebook.buck.rules.macros.WorkerMacroExpander; import com.facebook.buck.util.HumanReadableException; import com.facebook.buck.util.MoreCollectors; import com.facebook.buck.util.Optionals; import com.facebook.infer.annotation.SuppressFieldNotInitialized; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.util.Comparator; import java.util.Optional; import java.util.stream.Stream; public abstract class AbstractGenruleDescription<T extends AbstractGenruleDescription.CommonArg> implements Description<T>, ImplicitDepsInferringDescription<T> { public static final MacroHandler PARSE_TIME_MACRO_HANDLER = new MacroHandler( ImmutableMap.<String, MacroExpander>builder() .put("classpath", new ClasspathMacroExpander()) .put("exe", new ExecutableMacroExpander()) .put("worker", new WorkerMacroExpander()) .put("location", new LocationMacroExpander()) .put("maven_coords", new MavenCoordinatesMacroExpander()) .put("query_targets", new QueryTargetsMacroExpander(Optional.empty())) .put("query_outputs", new QueryOutputsMacroExpander(Optional.empty())) .build()); protected BuildRule createBuildRule( final BuildRuleParams params, @SuppressWarnings("unused") final BuildRuleResolver resolver, T args, Optional<com.facebook.buck.rules.args.Arg> cmd, Optional<com.facebook.buck.rules.args.Arg> bash, Optional<com.facebook.buck.rules.args.Arg> cmdExe) { return new Genrule(params, args.getSrcs(), cmd, bash, cmdExe, args.getType(), args.getOut()); } protected MacroHandler getMacroHandlerForParseTimeDeps() { return PARSE_TIME_MACRO_HANDLER; } protected Optional<MacroHandler> getMacroHandler( @SuppressWarnings("unused") BuildTarget buildTarget, @SuppressWarnings("unused") ProjectFilesystem filesystem, @SuppressWarnings("unused") BuildRuleResolver resolver, TargetGraph targetGraph, @SuppressWarnings("unused") T args) { return Optional.of( new MacroHandler( ImmutableMap.<String, MacroExpander>builder() .put("classpath", new ClasspathMacroExpander()) .put("exe", new ExecutableMacroExpander()) .put("worker", new WorkerMacroExpander()) .put("location", new LocationMacroExpander()) .put("maven_coords", new MavenCoordinatesMacroExpander()) .put("query_targets", new QueryTargetsMacroExpander(Optional.of(targetGraph))) .put("query_outputs", new QueryOutputsMacroExpander(Optional.of(targetGraph))) .build())); } @Override public BuildRule createBuildRule( final TargetGraph targetGraph, final BuildRuleParams params, final BuildRuleResolver resolver, CellPathResolver cellRoots, final T args) throws NoSuchBuildTargetException { Optional<MacroHandler> maybeMacroHandler = getMacroHandler( params.getBuildTarget(), params.getProjectFilesystem(), resolver, targetGraph, args); if (maybeMacroHandler.isPresent()) { MacroHandler macroHandler = maybeMacroHandler.get(); SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver); java.util.function.Function<String, com.facebook.buck.rules.args.Arg> macroArgFunction = MacroArg.toMacroArgFunction(macroHandler, params.getBuildTarget(), cellRoots, resolver) ::apply; final Optional<com.facebook.buck.rules.args.Arg> cmd = args.getCmd().map(macroArgFunction); final Optional<com.facebook.buck.rules.args.Arg> bash = args.getBash().map(macroArgFunction); final Optional<com.facebook.buck.rules.args.Arg> cmdExe = args.getCmdExe().map(macroArgFunction); return createBuildRule( params.copyReplacingExtraDeps( Suppliers.ofInstance( Stream.concat( ruleFinder.filterBuildRuleInputs(args.getSrcs()).stream(), Stream.of(cmd, bash, cmdExe) .flatMap(Optionals::toStream) .flatMap(input -> input.getDeps(ruleFinder).stream())) .collect( MoreCollectors.toImmutableSortedSet( Comparator.<BuildRule>naturalOrder())))), resolver, args, cmd, bash, cmdExe); } return createBuildRule( params, resolver, args, Optional.empty(), Optional.empty(), Optional.empty()); } @Override public void findDepsForTargetFromConstructorArgs( BuildTarget buildTarget, CellPathResolver cellRoots, T constructorArg, ImmutableCollection.Builder<BuildTarget> extraDepsBuilder, ImmutableCollection.Builder<BuildTarget> targetGraphOnlyDepsBuilder) { if (constructorArg.getBash().isPresent()) { addDepsFromParam( buildTarget, cellRoots, constructorArg.getBash().get(), extraDepsBuilder, targetGraphOnlyDepsBuilder); } if (constructorArg.getCmd().isPresent()) { addDepsFromParam( buildTarget, cellRoots, constructorArg.getCmd().get(), extraDepsBuilder, targetGraphOnlyDepsBuilder); } if (constructorArg.getCmdExe().isPresent()) { addDepsFromParam( buildTarget, cellRoots, constructorArg.getCmdExe().get(), extraDepsBuilder, targetGraphOnlyDepsBuilder); } } @Override public void findDepsForTargetFromConstructorArgs( BuildTarget buildTarget, CellPathResolver cellRoots, TargetGraph targetGraph, BuildRuleResolver resolver, SourcePathRuleFinder ruleFinder, ProjectFilesystem projectFilesystem, T constructorArg, ImmutableCollection.Builder<BuildTarget> extraDepsBuilder, ImmutableCollection.Builder<BuildTarget> nonBuildDepsBuilder) { Optional<MacroHandler> maybeMacroHandler = getMacroHandler(buildTarget, projectFilesystem, resolver, targetGraph, constructorArg); maybeMacroHandler.ifPresent( macroHandler -> { Stream.of(constructorArg.getCmd(), constructorArg.getCmd(), constructorArg.getCmdExe()) .flatMap(Optionals::toStream) .forEach( s -> { try { macroHandler.extractParseTimeDeps( buildTarget, cellRoots, s, extraDepsBuilder, nonBuildDepsBuilder); ImmutableList<BuildRule> buildDeps = macroHandler.extractBuildTimeDeps(buildTarget, cellRoots, resolver, s); for (BuildRule dep : buildDeps) { extraDepsBuilder.add(dep.getBuildTarget()); } } catch (MacroException e) { throw new HumanReadableException(e, "%s: %s", buildTarget, e.getMessage()); } }); }); } private void addDepsFromParam( BuildTarget target, CellPathResolver cellNames, String paramValue, ImmutableCollection.Builder<BuildTarget> extraDepsBuilder, ImmutableCollection.Builder<BuildTarget> targetGraphOnlyDepsBuilder) { try { getMacroHandlerForParseTimeDeps() .extractParseTimeDeps( target, cellNames, paramValue, extraDepsBuilder, targetGraphOnlyDepsBuilder); } catch (MacroException e) { throw new HumanReadableException(e, "%s: %s", target, e.getMessage()); } } @SuppressFieldNotInitialized public interface CommonArg extends CommonDescriptionArg, HasTests { String getOut(); Optional<String> getBash(); Optional<String> getCmd(); Optional<String> getCmdExe(); Optional<String> getType(); ImmutableList<SourcePath> getSrcs(); } }