diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/packages')
7 files changed, 211 insertions, 236 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/ExternalPackage.java b/src/main/java/com/google/devtools/build/lib/packages/ExternalPackage.java index 49852ee747..fda1a8321c 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/ExternalPackage.java +++ b/src/main/java/com/google/devtools/build/lib/packages/ExternalPackage.java @@ -24,7 +24,6 @@ import com.google.devtools.build.lib.cmdline.TargetParsingException; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.events.StoredEventHandler; import com.google.devtools.build.lib.packages.RuleFactory.InvalidRuleException; -import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.FuncallExpression; import com.google.devtools.build.lib.syntax.Label; import com.google.devtools.build.lib.syntax.Label.SyntaxException; @@ -121,8 +120,7 @@ public class ExternalPackage extends Package { attributes.put("actual", actual); } StoredEventHandler handler = new StoredEventHandler(); - Rule rule = RuleFactory.createRule( - this, bindRuleClass, attributes, handler, null, location, null); + Rule rule = RuleFactory.createRule(this, bindRuleClass, attributes, handler, null, location); overwriteRule(rule); rule.setVisibility(ConstantRuleVisibility.PUBLIC); } @@ -132,11 +130,11 @@ public class ExternalPackage extends Package { * WORKSPACE files to overwrite "earlier" ones. */ public Builder createAndAddRepositoryRule(RuleClass ruleClass, RuleClass bindRuleClass, - Map<String, Object> kwargs, FuncallExpression ast, Environment env) + Map<String, Object> kwargs, FuncallExpression ast) throws InvalidRuleException, NameConflictException, SyntaxException { StoredEventHandler eventHandler = new StoredEventHandler(); - Rule tempRule = RuleFactory.createRule( - this, ruleClass, kwargs, eventHandler, ast, ast.getLocation(), env); + Rule tempRule = RuleFactory.createRule(this, ruleClass, kwargs, eventHandler, ast, + ast.getLocation()); addEvents(eventHandler.getEvents()); try { repositoryMap.put(RepositoryName.create("@" + tempRule.getName()), tempRule); diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java index cde726bffb..ffea0bddad 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java +++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java @@ -46,9 +46,10 @@ import com.google.devtools.build.lib.syntax.FunctionSignature; import com.google.devtools.build.lib.syntax.GlobList; import com.google.devtools.build.lib.syntax.Identifier; import com.google.devtools.build.lib.syntax.Label; -import com.google.devtools.build.lib.syntax.Mutability; +import com.google.devtools.build.lib.syntax.MethodLibrary; import com.google.devtools.build.lib.syntax.ParserInputSource; import com.google.devtools.build.lib.syntax.Runtime; +import com.google.devtools.build.lib.syntax.SkylarkEnvironment; import com.google.devtools.build.lib.syntax.SkylarkSignature; import com.google.devtools.build.lib.syntax.SkylarkSignature.Param; import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor; @@ -325,6 +326,7 @@ public final class PackageFactory { private final RuleFactory ruleFactory; private final RuleClassProvider ruleClassProvider; + private final Environment globalEnv; private AtomicReference<? extends UnixGlob.FilesystemCalls> syscalls; private Preprocessor.Factory preprocessorFactory = Preprocessor.Factory.NullFactory.INSTANCE; @@ -365,6 +367,7 @@ public final class PackageFactory { this.platformSetRegexps = platformSetRegexps; this.ruleFactory = new RuleFactory(ruleClassProvider); this.ruleClassProvider = ruleClassProvider; + globalEnv = newGlobalEnvironment(); threadPool = new ThreadPoolExecutor(100, 100, 15L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactoryBuilder().setNameFormat("Legacy globber %d").build()); @@ -399,6 +402,15 @@ public final class PackageFactory { /** + * Returns the static environment initialized once and shared by all packages + * created by this factory. No updates occur to this environment once created. + */ + @VisibleForTesting + public Environment getEnvironment() { + return globalEnv; + } + + /** * Returns the immutable, unordered set of names of all the known rule * classes. */ @@ -619,8 +631,8 @@ public final class PackageFactory { "'environment_group argument'", context.pkgBuilder.getBuildFileLabel()); try { - context.pkgBuilder.addEnvironmentGroup( - name, environments, defaults, context.eventHandler, loc); + context.pkgBuilder.addEnvironmentGroup(name, environments, defaults, + context.eventHandler, loc); return Runtime.NONE; } catch (Label.SyntaxException e) { throw new EvalException(loc, @@ -898,7 +910,7 @@ public final class PackageFactory { Environment env) throws RuleFactory.InvalidRuleException, Package.NameConflictException { RuleClass ruleClass = getBuiltInRuleClass(ruleClassName, ruleFactory); - RuleFactory.createAndAddRule(context, ruleClass, kwargs, ast, env); + RuleFactory.createAndAddRule(context, ruleClass, kwargs, ast, env.getStackTrace()); } private static RuleClass getBuiltInRuleClass(String ruleClassName, RuleFactory ruleFactory) { @@ -946,6 +958,16 @@ public final class PackageFactory { }; } + /** + * Returns a new environment populated with common entries that can be shared + * across packages and that don't require the context. + */ + private static Environment newGlobalEnvironment() { + Environment env = new Environment(); + MethodLibrary.setupMethodEnvironment(env); + return env; + } + /**************************************************************************** * Package creation. */ @@ -973,7 +995,7 @@ public final class PackageFactory { Preprocessor.Result preprocessingResult, Iterable<Event> preprocessingEvents, List<Statement> preludeStatements, - Map<PathFragment, Environment> imports, + Map<PathFragment, SkylarkEnvironment> imports, ImmutableList<Label> skylarkFileDependencies, CachingPackageLocator locator, RuleVisibility defaultVisibility, @@ -1042,12 +1064,12 @@ public final class PackageFactory { packageId, buildFile, preprocessingResult, - /*preprocessingEvents=*/localReporter.getEvents(), - /*preludeStatements=*/ImmutableList.<Statement>of(), - /*imports=*/ImmutableMap.<PathFragment, Environment>of(), - /*skylarkFileDependencies=*/ImmutableList.<Label>of(), + localReporter.getEvents(), /* preprocessingEvents */ + ImmutableList.<Statement>of(), /* preludeStatements */ + ImmutableMap.<PathFragment, SkylarkEnvironment>of(), /* imports */ + ImmutableList.<Label>of(), /* skylarkFileDependencies */ locator, - /*defaultVisibility=*/ConstantRuleVisibility.PUBLIC, + ConstantRuleVisibility.PUBLIC, /* defaultVisibility */ globber) .build(); Event.replayEventsOn(eventHandler, result.getEvents()); @@ -1088,13 +1110,8 @@ public final class PackageFactory { return Preprocessor.Result.noPreprocessing(inputSource); } try { - return preprocessor.preprocess( - inputSource, - packageId.toString(), - globber, - eventHandler, - Environment.BUILD, - ruleFactory.getRuleClassNames()); + return preprocessor.preprocess(inputSource, packageId.toString(), globber, eventHandler, + globalEnv, ruleFactory.getRuleClassNames()); } catch (IOException e) { eventHandler.handle(Event.error(Location.fromFile(buildFile), "preprocessing failed: " + e.getMessage())); @@ -1195,20 +1212,19 @@ public final class PackageFactory { // or if not possible, at least make them straight copies from the native module variant. // or better, use a common Environment.Frame for these common bindings // (that shares a backing ImmutableMap for the bindings?) - pkgEnv - .setup("native", nativeModule) - .setup("distribs", newDistribsFunction.apply(context)) - .setup("glob", newGlobFunction.apply(context, /*async=*/false)) - .setup("mocksubinclude", newMockSubincludeFunction.apply(context)) - .setup("licenses", newLicensesFunction.apply(context)) - .setup("exports_files", newExportsFilesFunction.apply()) - .setup("package_group", newPackageGroupFunction.apply()) - .setup("package", newPackageFunction(packageArguments)) - .setup("environment_group", newEnvironmentGroupFunction.apply(context)); + pkgEnv.update("native", nativeModule); + pkgEnv.update("distribs", newDistribsFunction.apply(context)); + pkgEnv.update("glob", newGlobFunction.apply(context, /*async=*/false)); + pkgEnv.update("mocksubinclude", newMockSubincludeFunction.apply(context)); + pkgEnv.update("licenses", newLicensesFunction.apply(context)); + pkgEnv.update("exports_files", newExportsFilesFunction.apply()); + pkgEnv.update("package_group", newPackageGroupFunction.apply()); + pkgEnv.update("package", newPackageFunction(packageArguments)); + pkgEnv.update("environment_group", newEnvironmentGroupFunction.apply(context)); for (String ruleClass : ruleFactory.getRuleClassNames()) { BaseFunction ruleFunction = newRuleFunction(ruleFactory, ruleClass); - pkgEnv.setup(ruleClass, ruleFunction); + pkgEnv.update(ruleClass, ruleFunction); } for (EnvironmentExtension extension : environmentExtensions) { @@ -1239,65 +1255,62 @@ public final class PackageFactory { PackageIdentifier packageId, BuildFileAST buildFileAST, Path buildFilePath, Globber globber, Iterable<Event> pastEvents, RuleVisibility defaultVisibility, boolean containsError, boolean containsTransientError, MakeEnvironment.Builder pkgMakeEnv, - Map<PathFragment, Environment> imports, + Map<PathFragment, SkylarkEnvironment> imports, ImmutableList<Label> skylarkFileDependencies) throws InterruptedException { + // Important: Environment should be unreachable by the end of this method! + StoredEventHandler eventHandler = new StoredEventHandler(); + Environment pkgEnv = new Environment(globalEnv, eventHandler); + pkgEnv.setLoadingPhase(); + Package.LegacyBuilder pkgBuilder = new Package.LegacyBuilder( packageId, ruleClassProvider.getRunfilesPrefix()); - StoredEventHandler eventHandler = new StoredEventHandler(); - try (Mutability mutability = Mutability.create("package %s", packageId)) { - Environment pkgEnv = Environment.builder(mutability) - .setGlobals(Environment.BUILD) - .setEventHandler(eventHandler) - .setImportedExtensions(imports) - .setLoadingPhase() - .build(); - - pkgBuilder.setGlobber(globber) - .setFilename(buildFilePath) - .setMakeEnv(pkgMakeEnv) - .setDefaultVisibility(defaultVisibility) - // "defaultVisibility" comes from the command line. Let's give the BUILD file a chance to - // set default_visibility once, be reseting the PackageBuilder.defaultVisibilitySet flag. - .setDefaultVisibilitySet(false) - .setSkylarkFileDependencies(skylarkFileDependencies) - .setWorkspaceName(externalPkg.getWorkspaceName()); - - Event.replayEventsOn(eventHandler, pastEvents); - - // Stuff that closes over the package context: - PackageContext context = new PackageContext(pkgBuilder, globber, eventHandler); - buildPkgEnv(pkgEnv, context, ruleFactory); - pkgEnv.setupDynamic(PKG_CONTEXT, context); - pkgEnv.setupDynamic(Runtime.PKG_NAME, packageId.toString()); - - if (containsError) { - pkgBuilder.setContainsErrors(); - } + pkgBuilder.setGlobber(globber) + .setFilename(buildFilePath) + .setMakeEnv(pkgMakeEnv) + .setDefaultVisibility(defaultVisibility) + // "defaultVisibility" comes from the command line. Let's give the BUILD file a chance to + // set default_visibility once, be reseting the PackageBuilder.defaultVisibilitySet flag. + .setDefaultVisibilitySet(false) + .setSkylarkFileDependencies(skylarkFileDependencies) + .setWorkspaceName(externalPkg.getWorkspaceName()); - if (containsTransientError) { - pkgBuilder.setContainsTemporaryErrors(); - } + Event.replayEventsOn(eventHandler, pastEvents); - if (!validatePackageIdentifier(packageId, buildFileAST.getLocation(), eventHandler)) { - pkgBuilder.setContainsErrors(); - } + // Stuff that closes over the package context:` + PackageContext context = new PackageContext(pkgBuilder, globber, eventHandler); + buildPkgEnv(pkgEnv, context, ruleFactory); - if (!validateAssignmentStatements(pkgEnv, buildFileAST, eventHandler)) { - pkgBuilder.setContainsErrors(); - } + if (containsError) { + pkgBuilder.setContainsErrors(); + } - if (buildFileAST.containsErrors()) { - pkgBuilder.setContainsErrors(); - } + if (containsTransientError) { + pkgBuilder.setContainsTemporaryErrors(); + } - // TODO(bazel-team): (2009) the invariant "if errors are reported, mark the package - // as containing errors" is strewn all over this class. Refactor to use an - // event sensor--and see if we can simplify the calling code in - // createPackage(). - if (!buildFileAST.exec(pkgEnv, eventHandler)) { - pkgBuilder.setContainsErrors(); - } + if (!validatePackageIdentifier(packageId, buildFileAST.getLocation(), eventHandler)) { + pkgBuilder.setContainsErrors(); + } + + pkgEnv.setImportedExtensions(imports); + pkgEnv.updateAndPropagate(PKG_CONTEXT, context); + pkgEnv.updateAndPropagate(Runtime.PKG_NAME, packageId.toString()); + + if (!validateAssignmentStatements(pkgEnv, buildFileAST, eventHandler)) { + pkgBuilder.setContainsErrors(); + } + + if (buildFileAST.containsErrors()) { + pkgBuilder.setContainsErrors(); + } + + // TODO(bazel-team): (2009) the invariant "if errors are reported, mark the package + // as containing errors" is strewn all over this class. Refactor to use an + // event sensor--and see if we can simplify the calling code in + // createPackage(). + if (!buildFileAST.exec(pkgEnv, eventHandler)) { + pkgBuilder.setContainsErrors(); } pkgBuilder.addEvents(eventHandler.getEvents()); @@ -1316,36 +1329,29 @@ public final class PackageFactory { // of all globs. return; } - try (Mutability mutability = Mutability.create("prefetchGlobs for %s", packageId)) { - Environment pkgEnv = Environment.builder(mutability) - .setGlobals(Environment.BUILD) - .setEventHandler(NullEventHandler.INSTANCE) - .setLoadingPhase() - .build(); - - Package.LegacyBuilder pkgBuilder = new Package.LegacyBuilder(packageId, - ruleClassProvider.getRunfilesPrefix()); - - pkgBuilder.setFilename(buildFilePath) - .setMakeEnv(pkgMakeEnv) - .setDefaultVisibility(defaultVisibility) - // "defaultVisibility" comes from the command line. Let's give the BUILD file a chance to - // set default_visibility once, be reseting the PackageBuilder.defaultVisibilitySet flag. - .setDefaultVisibilitySet(false); - - // Stuff that closes over the package context: - PackageContext context = new PackageContext(pkgBuilder, globber, NullEventHandler.INSTANCE); - buildPkgEnv(pkgEnv, context, ruleFactory); - try { - pkgEnv.update("glob", newGlobFunction.apply(context, /*async=*/true)); - // The Fileset function is heavyweight in that it can run glob(). Avoid this during the - // preloading phase. - pkgEnv.update("FilesetEntry", Runtime.NONE); - } catch (EvalException e) { - throw new AssertionError(e); - } - buildFileAST.exec(pkgEnv, NullEventHandler.INSTANCE); - } + // Important: Environment should be unreachable by the end of this method! + Environment pkgEnv = new Environment(); + pkgEnv.setLoadingPhase(); + + Package.LegacyBuilder pkgBuilder = new Package.LegacyBuilder(packageId, + ruleClassProvider.getRunfilesPrefix()); + + pkgBuilder.setFilename(buildFilePath) + .setMakeEnv(pkgMakeEnv) + .setDefaultVisibility(defaultVisibility) + // "defaultVisibility" comes from the command line. Let's give the BUILD file a chance to + // set default_visibility once, be reseting the PackageBuilder.defaultVisibilitySet flag. + .setDefaultVisibilitySet(false); + + // Stuff that closes over the package context: + PackageContext context = new PackageContext(pkgBuilder, globber, NullEventHandler.INSTANCE); + buildPkgEnv(pkgEnv, context, ruleFactory); + pkgEnv.update("glob", newGlobFunction.apply(context, /*async=*/true)); + // The Fileset function is heavyweight in that it can run glob(). Avoid this during the + // preloading phase. + pkgEnv.remove("FilesetEntry"); + + buildFileAST.exec(pkgEnv, NullEventHandler.INSTANCE); } diff --git a/src/main/java/com/google/devtools/build/lib/packages/Preprocessor.java b/src/main/java/com/google/devtools/build/lib/packages/Preprocessor.java index c44776ad8b..a479ca9f55 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/Preprocessor.java +++ b/src/main/java/com/google/devtools/build/lib/packages/Preprocessor.java @@ -141,7 +141,7 @@ public interface Preprocessor { * @param packageName the BUILD file's package. * @param globber a globber for evaluating globs. * @param eventHandler a eventHandler on which to report warnings/errors. - * @param globals the global bindings for the Python environment. + * @param globalEnv the GLOBALS Python environment. * @param ruleNames the set of names of all rules in the build language. * @throws IOException if there was an I/O problem during preprocessing. * @return a pair of the ParserInputSource and a map of subincludes seen during the evaluation @@ -151,7 +151,7 @@ public interface Preprocessor { String packageName, Globber globber, EventHandler eventHandler, - Environment.Frame globals, + Environment globalEnv, Set<String> ruleNames) throws IOException, InterruptedException; } diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java index 7906a2bcda..59fcbb595b 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java +++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java @@ -34,13 +34,13 @@ import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; import com.google.devtools.build.lib.syntax.Argument; import com.google.devtools.build.lib.syntax.BaseFunction; -import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.FragmentClassNameResolver; import com.google.devtools.build.lib.syntax.FuncallExpression; import com.google.devtools.build.lib.syntax.GlobList; import com.google.devtools.build.lib.syntax.Label; import com.google.devtools.build.lib.syntax.Label.SyntaxException; import com.google.devtools.build.lib.syntax.Runtime; +import com.google.devtools.build.lib.syntax.SkylarkEnvironment; import com.google.devtools.build.lib.util.StringUtil; import com.google.devtools.build.lib.vfs.PathFragment; @@ -498,7 +498,7 @@ public final class RuleClass { private BaseFunction configuredTargetFunction = null; private Function<? super Rule, Map<String, Label>> externalBindingsFunction = NO_EXTERNAL_BINDINGS; - private Environment ruleDefinitionEnvironment = null; + private SkylarkEnvironment ruleDefinitionEnvironment = null; private Set<Class<?>> configurationFragments = new LinkedHashSet<>(); private MissingFragmentPolicy missingFragmentPolicy = MissingFragmentPolicy.FAIL_ANALYSIS; private Set<String> requiredFragmentNames = new LinkedHashSet<>(); @@ -792,7 +792,7 @@ public final class RuleClass { /** * Sets the rule definition environment. Meant for Skylark usage. */ - public Builder setRuleDefinitionEnvironment(Environment env) { + public Builder setRuleDefinitionEnvironment(SkylarkEnvironment env) { this.ruleDefinitionEnvironment = env; return this; } @@ -964,7 +964,7 @@ public final class RuleClass { * The Skylark rule definition environment of this RuleClass. * Null for non Skylark executable RuleClasses. */ - @Nullable private final Environment ruleDefinitionEnvironment; + @Nullable private final SkylarkEnvironment ruleDefinitionEnvironment; /** * The set of required configuration fragments; this should list all fragments that can be @@ -1015,7 +1015,7 @@ public final class RuleClass { ImmutableSet<Class<?>> advertisedProviders, @Nullable BaseFunction configuredTargetFunction, Function<? super Rule, Map<String, Label>> externalBindingsFunction, - @Nullable Environment ruleDefinitionEnvironment, + @Nullable SkylarkEnvironment ruleDefinitionEnvironment, Set<Class<?>> allowedConfigurationFragments, MissingFragmentPolicy missingFragmentPolicy, boolean supportsConstraintChecking, @@ -1076,7 +1076,7 @@ public final class RuleClass { ImmutableSet<Class<?>> advertisedProviders, @Nullable BaseFunction configuredTargetFunction, Function<? super Rule, Map<String, Label>> externalBindingsFunction, - @Nullable Environment ruleDefinitionEnvironment, + @Nullable SkylarkEnvironment ruleDefinitionEnvironment, Set<Class<?>> allowedConfigurationFragments, Set<String> allowedConfigurationFragmentNames, @Nullable FragmentClassNameResolver fragmentNameResolver, @@ -1725,7 +1725,7 @@ public final class RuleClass { /** * Returns this RuleClass's rule definition environment. */ - @Nullable public Environment getRuleDefinitionEnvironment() { + @Nullable public SkylarkEnvironment getRuleDefinitionEnvironment() { return ruleDefinitionEnvironment; } diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java index b3ca83fe36..958d88ac7c 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java @@ -15,14 +15,12 @@ package com.google.devtools.build.lib.packages; import com.google.devtools.build.lib.events.EventHandler; -import com.google.devtools.build.lib.syntax.Environment; -import com.google.devtools.build.lib.syntax.Mutability; +import com.google.devtools.build.lib.syntax.SkylarkEnvironment; +import com.google.devtools.build.lib.syntax.ValidationEnvironment; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Map; -import javax.annotation.Nullable; - /** * The collection of the supported build rules. Provides an Environment for Skylark rule creation. */ @@ -49,19 +47,17 @@ public interface RuleClassProvider { Map<String, Class<? extends AspectFactory<?, ?, ?>>> getAspectFactoryMap(); /** - * Returns a new Skylark Environment instance for rule creation. - * Implementations need to be thread safe. - * Be sure to close() the mutability before you return the results of said evaluation. - * @param mutability the Mutability for the current evaluation context - * @param eventHandler the EventHandler for warnings, errors, etc. - * @param astFileContentHashCode the hash code identifying this environment. - * @return an Environment, in which to evaluate load time skylark forms. + * Returns a new Skylark Environment instance for rule creation. Implementations need to be + * thread safe. + */ + SkylarkEnvironment createSkylarkRuleClassEnvironment( + EventHandler eventHandler, String astFileContentHashCode); + + /** + * Returns a validation environment for static analysis of skylark files. + * The environment has to contain all built-in functions and objects. */ - Environment createSkylarkRuleClassEnvironment( - Mutability mutability, - EventHandler eventHandler, - @Nullable String astFileContentHashCode, - @Nullable Map<PathFragment, Environment> importMap); + ValidationEnvironment getSkylarkValidationEnvironment(); /** * Returns the default content of the WORKSPACE file. diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java b/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java index 2eb94b19d9..33f9d49793 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java +++ b/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java @@ -15,24 +15,20 @@ package com.google.devtools.build.lib.packages; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.packages.Package.NameConflictException; import com.google.devtools.build.lib.packages.PackageFactory.PackageContext; -import com.google.devtools.build.lib.syntax.BaseFunction; -import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.FuncallExpression; import com.google.devtools.build.lib.syntax.Label; import com.google.devtools.build.lib.syntax.Label.SyntaxException; -import com.google.devtools.build.lib.syntax.UserDefinedFunction; -import com.google.devtools.build.lib.util.Pair; +import com.google.devtools.build.lib.syntax.StackTraceElement; import java.util.Map; import java.util.Set; -import javax.annotation.Nullable; - /** * Given a rule class and a set of attributes, returns a Rule instance. Also * performs a number of checks and associates the rule and the owning package @@ -82,7 +78,7 @@ public class RuleFactory { EventHandler eventHandler, FuncallExpression ast, Location location, - @Nullable Environment env) + ImmutableList<StackTraceElement> stackTrace) throws InvalidRuleException { Preconditions.checkNotNull(ruleClass); String ruleClassName = ruleClass.getName(); @@ -112,19 +108,31 @@ public class RuleFactory { } try { - return ruleClass.createRuleWithLabel( - pkgBuilder, - label, - addGeneratorAttributesForMacros(attributeValues, env), - eventHandler, - ast, + Rule rule = ruleClass.createRuleWithLabel(pkgBuilder, label, + addGeneratorAttributesForMacros(attributeValues, stackTrace), eventHandler, ast, location); + return rule; } catch (SyntaxException e) { throw new RuleFactory.InvalidRuleException(ruleClass + " " + e.getMessage()); } } /** + * Creates and returns a rule instance (without a stack trace). + */ + static Rule createRule( + Package.Builder pkgBuilder, + RuleClass ruleClass, + Map<String, Object> attributeValues, + EventHandler eventHandler, + FuncallExpression ast, + Location location) + throws InvalidRuleException { + return createRule(pkgBuilder, ruleClass, attributeValues, eventHandler, ast, location, + ImmutableList.<StackTraceElement>of()); + } + + /** * Creates a rule instance, adds it to the package and returns it. * * @param pkgBuilder the under-construction package to which the rule belongs @@ -137,40 +145,34 @@ public class RuleFactory { * rule creation * @param ast the abstract syntax tree of the rule expression (optional) * @param location the location at which this rule was declared + * @param stackTrace the stack trace containing all functions that led to the creation of + * this rule (optional) * @throws InvalidRuleException if the rule could not be constructed for any * reason (e.g. no <code>name</code> attribute is defined) - * @throws InvalidRuleException, NameConflictException + * @throws NameConflictException */ - static Rule createAndAddRule( - Package.Builder pkgBuilder, - RuleClass ruleClass, - Map<String, Object> attributeValues, - EventHandler eventHandler, - FuncallExpression ast, - Location location, - Environment env) + static Rule createAndAddRule(Package.Builder pkgBuilder, + RuleClass ruleClass, + Map<String, Object> attributeValues, + EventHandler eventHandler, + FuncallExpression ast, + Location location, + ImmutableList<StackTraceElement> stackTrace) throws InvalidRuleException, NameConflictException { Rule rule = createRule( - pkgBuilder, ruleClass, attributeValues, eventHandler, ast, location, env); + pkgBuilder, ruleClass, attributeValues, eventHandler, ast, location, stackTrace); pkgBuilder.addRule(rule); return rule; } - public static Rule createAndAddRule( - PackageContext context, + public static Rule createAndAddRule(PackageContext context, RuleClass ruleClass, Map<String, Object> attributeValues, FuncallExpression ast, - Environment env) + ImmutableList<StackTraceElement> stackTrace) throws InvalidRuleException, NameConflictException { - return createAndAddRule( - context.pkgBuilder, - ruleClass, - attributeValues, - context.eventHandler, - ast, - ast.getLocation(), - env); + return createAndAddRule(context.pkgBuilder, ruleClass, attributeValues, context.eventHandler, + ast, ast.getLocation(), stackTrace); } /** @@ -190,28 +192,22 @@ public class RuleFactory { * <p>Otherwise, it returns the given attributes without any changes. */ private static Map<String, Object> addGeneratorAttributesForMacros( - Map<String, Object> args, @Nullable Environment env) { - // Returns the original arguments if a) there is only the rule itself on the stack - // trace (=> no macro) or b) the attributes have already been set by Python pre-processing. - if (env == null) { - return args; - } - boolean hasName = args.containsKey("generator_name"); - boolean hasFunc = args.containsKey("generator_function"); - // TODO(bazel-team): resolve cases in our code where hasName && !hasFunc, or hasFunc && !hasName - if (hasName || hasFunc) { - return args; - } - Pair<BaseFunction, Location> topCall = env.getTopCall(); - if (topCall == null || !(topCall.first instanceof UserDefinedFunction)) { + Map<String, Object> args, ImmutableList<StackTraceElement> stackTrace) { + if (stackTrace.size() <= 2 || args.containsKey("generator_name") + || args.containsKey("generator_function")) { + // Returns the original arguments if a) there is only the rule itself on the stack + // trace (=> no macro) or b) the attributes have already been set by Python pre-processing. + // The stack trace will always have at least two entries: one for the call to the rule and one + // for its implementation. Consequently, we check for size <= 2. return args; } + StackTraceElement generator = stackTrace.get(0); ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder(); builder.putAll(args); builder.put("generator_name", args.get("name")); - builder.put("generator_function", topCall.first.getName()); - builder.put("generator_location", topCall.second.toString()); + builder.put("generator_function", generator.getName()); + builder.put("generator_location", Location.printPathAndLine(generator.getLocation())); try { return builder.build(); diff --git a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java index abbbdf88d3..054865fafd 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java +++ b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java @@ -29,7 +29,7 @@ import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.FuncallExpression; import com.google.devtools.build.lib.syntax.FunctionSignature; import com.google.devtools.build.lib.syntax.Label; -import com.google.devtools.build.lib.syntax.Mutability; +import com.google.devtools.build.lib.syntax.MethodLibrary; import com.google.devtools.build.lib.syntax.ParserInputSource; import java.io.File; @@ -44,30 +44,14 @@ public class WorkspaceFactory { private final Builder builder; private final Environment environment; - /** - * @param builder a builder for the Workspace - * @param ruleClassProvider a provider for known rule classes - * @param mutability the Mutability for the current evaluation context - */ - public WorkspaceFactory( - Builder builder, RuleClassProvider ruleClassProvider, Mutability mutability) { - this(builder, ruleClassProvider, mutability, null); + public WorkspaceFactory(Builder builder, RuleClassProvider ruleClassProvider) { + this(builder, ruleClassProvider, null); } - // TODO(bazel-team): document installDir - /** - * @param builder a builder for the Workspace - * @param ruleClassProvider a provider for known rule classes - * @param mutability the Mutability for the current evaluation context - * @param installDir an optional directory into which to install software - */ public WorkspaceFactory( - Builder builder, - RuleClassProvider ruleClassProvider, - Mutability mutability, - @Nullable String installDir) { + Builder builder, RuleClassProvider ruleClassProvider, @Nullable String installDir) { this.builder = builder; - this.environment = createWorkspaceEnv(builder, ruleClassProvider, mutability, installDir); + this.environment = createWorkspaceEnv(builder, ruleClassProvider, installDir); } public void parse(ParserInputSource source) @@ -138,13 +122,13 @@ public class WorkspaceFactory { private static BuiltinFunction newRuleFunction( final RuleFactory ruleFactory, final Builder builder, final String ruleClassName) { return new BuiltinFunction(ruleClassName, - FunctionSignature.KWARGS, BuiltinFunction.USE_AST_ENV) { - public Object invoke(Map<String, Object> kwargs, FuncallExpression ast, Environment env) + FunctionSignature.KWARGS, BuiltinFunction.USE_AST) { + public Object invoke(Map<String, Object> kwargs, FuncallExpression ast) throws EvalException { try { RuleClass ruleClass = ruleFactory.getRuleClass(ruleClassName); RuleClass bindRuleClass = ruleFactory.getRuleClass("bind"); - builder.createAndAddRepositoryRule(ruleClass, bindRuleClass, kwargs, ast, env); + builder.createAndAddRepositoryRule(ruleClass, bindRuleClass, kwargs, ast); } catch (RuleFactory.InvalidRuleException | Package.NameConflictException | Label.SyntaxException e) { throw new EvalException(ast.getLocation(), e.getMessage()); @@ -155,30 +139,25 @@ public class WorkspaceFactory { } private Environment createWorkspaceEnv( - Builder builder, - RuleClassProvider ruleClassProvider, - Mutability mutability, - String installDir) { - Environment workspaceEnv = Environment.builder(mutability) - .setGlobals(Environment.BUILD) - .setLoadingPhase() - .build(); + Builder builder, RuleClassProvider ruleClassProvider, String installDir) { + Environment workspaceEnv = new Environment(); + MethodLibrary.setupMethodEnvironment(workspaceEnv); + workspaceEnv.setLoadingPhase(); + RuleFactory ruleFactory = new RuleFactory(ruleClassProvider); - try { - for (String ruleClass : ruleFactory.getRuleClassNames()) { - BaseFunction ruleFunction = newRuleFunction(ruleFactory, builder, ruleClass); - workspaceEnv.update(ruleClass, ruleFunction); - } - if (installDir != null) { - workspaceEnv.update("__embedded_dir__", installDir); - } - File jreDirectory = new File(System.getProperty("java.home")); - workspaceEnv.update("DEFAULT_SERVER_JAVABASE", jreDirectory.getParentFile().toString()); - workspaceEnv.update("bind", newBindFunction(ruleFactory, builder)); - workspaceEnv.update("workspace", newWorkspaceNameFunction(builder)); - return workspaceEnv; - } catch (EvalException e) { - throw new AssertionError(e); + for (String ruleClass : ruleFactory.getRuleClassNames()) { + BaseFunction ruleFunction = newRuleFunction(ruleFactory, builder, ruleClass); + workspaceEnv.update(ruleClass, ruleFunction); } + + if (installDir != null) { + workspaceEnv.update("__embedded_dir__", installDir); + } + File jreDirectory = new File(System.getProperty("java.home")); + workspaceEnv.update("DEFAULT_SERVER_JAVABASE", jreDirectory.getParentFile().toString()); + + workspaceEnv.update("bind", newBindFunction(ruleFactory, builder)); + workspaceEnv.update("workspace", newWorkspaceNameFunction(builder)); + return workspaceEnv; } } |