/* * Copyright 2014-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.model.BuildTarget; import com.facebook.buck.model.MacroException; 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.HasDeclaredDeps; import com.facebook.buck.rules.ImplicitDepsInferringDescription; import com.facebook.buck.rules.PathSourcePath; 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.args.SourcePathArg; 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.MacroHandler; import com.facebook.buck.util.HumanReadableException; import com.facebook.buck.util.MoreCollectors; import com.facebook.buck.util.Optionals; import com.facebook.buck.util.immutables.BuckStyleImmutable; import com.google.common.base.Function; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; import java.nio.file.Path; import java.util.Optional; import java.util.stream.Stream; import org.immutables.value.Value; public class ShTestDescription implements Description<ShTestDescriptionArg>, ImplicitDepsInferringDescription<ShTestDescription.AbstractShTestDescriptionArg> { private static final MacroHandler MACRO_HANDLER = new MacroHandler( ImmutableMap.of( "location", new LocationMacroExpander(), "classpath", new ClasspathMacroExpander(), "exe", new ExecutableMacroExpander())); private final Optional<Long> defaultTestRuleTimeoutMs; public ShTestDescription(Optional<Long> defaultTestRuleTimeoutMs) { this.defaultTestRuleTimeoutMs = defaultTestRuleTimeoutMs; } @Override public Class<ShTestDescriptionArg> getConstructorArgType() { return ShTestDescriptionArg.class; } @Override public ShTest createBuildRule( TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, CellPathResolver cellRoots, ShTestDescriptionArg args) { SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver); Function<String, com.facebook.buck.rules.args.Arg> toArg = MacroArg.toMacroArgFunction(MACRO_HANDLER, params.getBuildTarget(), cellRoots, resolver); final ImmutableList<com.facebook.buck.rules.args.Arg> testArgs = Stream.concat( Optionals.toStream(args.getTest()).map(SourcePathArg::of), args.getArgs().stream().map(toArg::apply)) .collect(MoreCollectors.toImmutableList()); final ImmutableMap<String, com.facebook.buck.rules.args.Arg> testEnv = ImmutableMap.copyOf(Maps.transformValues(args.getEnv(), toArg)); return new ShTest( params.copyAppendingExtraDeps( () -> FluentIterable.from(testArgs) .append(testEnv.values()) .transformAndConcat(arg -> arg.getDeps(ruleFinder))), ruleFinder, testArgs, testEnv, FluentIterable.from(args.getResources()) .transform(p -> new PathSourcePath(params.getProjectFilesystem(), p)) .toSortedSet(Ordering.natural()), args.getTestRuleTimeoutMs().map(Optional::of).orElse(defaultTestRuleTimeoutMs), args.getRunTestSeparately(), args.getLabels(), args.getContacts()); } @Override public void findDepsForTargetFromConstructorArgs( BuildTarget buildTarget, CellPathResolver cellRoots, AbstractShTestDescriptionArg constructorArg, ImmutableCollection.Builder<BuildTarget> extraDepsBuilder, ImmutableCollection.Builder<BuildTarget> targetGraphOnlyDepsBuilder) { // Add parse time deps for any macros. for (String blob : Iterables.concat(constructorArg.getArgs(), constructorArg.getEnv().values())) { try { MACRO_HANDLER.extractParseTimeDeps( buildTarget, cellRoots, blob, extraDepsBuilder, targetGraphOnlyDepsBuilder); } catch (MacroException e) { throw new HumanReadableException(e, "%s: %s", buildTarget, e.getMessage()); } } } @BuckStyleImmutable @Value.Immutable interface AbstractShTestDescriptionArg extends CommonDescriptionArg, HasDeclaredDeps { Optional<SourcePath> getTest(); ImmutableList<String> getArgs(); ImmutableSet<String> getContacts(); Optional<Long> getTestRuleTimeoutMs(); @Value.Default default boolean getRunTestSeparately() { return false; } @Value.NaturalOrder ImmutableSortedSet<Path> getResources(); ImmutableMap<String, String> getEnv(); } }