// Copyright 2014 Google Inc. All rights reserved. // // 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.google.devtools.build.lib.packages; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.devtools.build.lib.cmdline.LabelValidator; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.events.NullEventHandler; import com.google.devtools.build.lib.events.StoredEventHandler; import com.google.devtools.build.lib.packages.GlobCache.BadGlobException; import com.google.devtools.build.lib.packages.License.DistributionType; import com.google.devtools.build.lib.packages.Type.ConversionException; import com.google.devtools.build.lib.syntax.AbstractFunction; import com.google.devtools.build.lib.syntax.AssignmentStatement; import com.google.devtools.build.lib.syntax.BuildFileAST; import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.Environment.NoSuchVariableException; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.Expression; import com.google.devtools.build.lib.syntax.FuncallExpression; import com.google.devtools.build.lib.syntax.Function; import com.google.devtools.build.lib.syntax.GlobList; import com.google.devtools.build.lib.syntax.Ident; import com.google.devtools.build.lib.syntax.Label; import com.google.devtools.build.lib.syntax.MixedModeFunction; import com.google.devtools.build.lib.syntax.ParserInputSource; import com.google.devtools.build.lib.syntax.SkylarkEnvironment; import com.google.devtools.build.lib.syntax.Statement; import com.google.devtools.build.lib.util.Pair; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.UnixGlob; import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Logger; import javax.annotation.Nullable; /** * The package factory is responsible for constructing Package instances * from a BUILD file's abstract syntax tree (AST). * *

A PackageFactory is a heavy-weight object; create them sparingly. * Typically only one is needed per client application. */ public final class PackageFactory { /** * An argument to the {@code package()} function. */ public abstract static class PackageArgument { private final String name; private final Type type; protected PackageArgument(String name, Type type) { this.name = name; this.type = type; } public String getName() { return name; } private void convertAndProcess( Package.LegacyBuilder pkgBuilder, Location location, Object value) throws EvalException, ConversionException { T typedValue = type.convert(value, "'package' argument", pkgBuilder.getBuildFileLabel()); process(pkgBuilder, location, typedValue); } /** * Process an argument. * * @param pkgBuilder the package builder to be mutated * @param location the location of the {@code package} function for error reporting * @param value the value of the argument. Typically passed to {@link Type#convert} */ protected abstract void process( Package.LegacyBuilder pkgBuilder, Location location, T value) throws EvalException; } /** Interface for evaluating globs during package loading. */ public static interface Globber { /** An opaque token for fetching the result of a glob computation. */ abstract static class Token {} /** * Asynchronously starts the given glob computation and returns a token for fetching the * result. */ Token runAsync(List includes, List excludes, boolean excludeDirs) throws BadGlobException; /** Fetches the result of a previously started glob computation. */ List fetch(Token token) throws IOException, InterruptedException; /** Should be called when the globber is about to be discarded due to an interrupt. */ void onInterrupt(); /** Should be called when the globber is no longer needed. */ void onCompletion(); /** Returns all the glob computations requested before {@link #onCompletion} was called. */ Set> getGlobPatterns(); } /** * An extension to the global namespace of the BUILD language. */ public interface EnvironmentExtension { /** * Update the global environment with the identifiers this extension contributes. */ void update(Environment environment, MakeEnvironment.Builder pkgMakeEnv, Label buildFileLabel); Iterable> getPackageArguments(); } private static final int EXCLUDE_DIR_DEFAULT = 1; private static class DefaultVisibility extends PackageArgument> { private DefaultVisibility() { super("default_visibility", Type.LABEL_LIST); } @Override protected void process(Package.LegacyBuilder pkgBuilder, Location location, List

{@code
   *   environment_group(
   *       name = "sample_group",
   *       environments = [":env1", ":env2", ...],
   *       defaults = [":env1", ...]
   *   )
   * }
* *

Where ":env1", "env2", ... are all environment rules declared in the same package. All * parameters are mandatory. */ private static Function newEnvironmentGroupFunction(final PackageContext context) { List params = ImmutableList.of("name", "environments", "defaults"); return new MixedModeFunction("environment_group", params, params.size(), true) { @Override public Object call(Object[] namedArgs, FuncallExpression ast) throws EvalException, ConversionException { Preconditions.checkState(namedArgs[0] != null); String name = Type.STRING.convert(namedArgs[0], "'environment_group' argument"); Preconditions.checkState(namedArgs[1] != null); List