aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java
diff options
context:
space:
mode:
authorGravatar John Field <jfield@google.com>2015-09-21 18:59:19 +0000
committerGravatar Laszlo Csomor <laszlocsomor@google.com>2015-09-22 17:05:23 +0000
commit925dc5ce1c6916b43a94fa12017aa4a6390de891 (patch)
tree17da1c801a23290c563bcf4347dd90930f094c12 /src/main/java
parentd256a821f4051273e3be1617c793c6dc5e77d964 (diff)
Use Labels, rather than PathFragments, to represent Skylark loads internally. This should be a semantics-preserving change for users. In a subsequent CL, I'll change the Skylark syntax to allow load statements to use labels as well as paths, with the goal of eventually deprecating the latter.
Also: - Removed the hack for handling relative loads in the prelude file. - Refactored some redundant functionality in PackageFunction and SkylarkImportLookupFunction for handling loads. - Removed the ability to put the BUILD file for the package containing a Skylark file under a different package root than the Skylark file itself. This functionality isn't currently used and is inconsistent with Blaze's handling of the package path elsewhere. - Added BUILD files to a number of tests that load Skylark files; this is consistent with the requirement that all Skylark files need to be part of some package. - Changed the constants used to set the location of the prelude file from paths to labels. -- MOS_MIGRATED_REVID=103567562
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java30
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/RuleClassProvider.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java198
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupValue.java94
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java73
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java149
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupValue.java42
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java16
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/LoadStatement.java24
-rw-r--r--src/main/java/com/google/devtools/build/skyframe/SkyFunctionException.java2
13 files changed, 288 insertions, 353 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
index 3b7ddd47e3..b46fea748c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType.ABSTRACT;
import static com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType.TEST;
-import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
@@ -81,7 +80,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
*/
public static class Builder implements RuleDefinitionEnvironment {
private final StringBuilder defaultWorkspaceFile = new StringBuilder();
- private PathFragment preludePath;
+ private Label preludeLabel;
private String runfilesPrefix;
private final List<ConfigurationFragmentFactory> configurationFragments = new ArrayList<>();
private final List<BuildInfoFactory> buildInfoFactories = new ArrayList<>();
@@ -105,11 +104,14 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
defaultWorkspaceFile.append(contents);
}
- public Builder setPrelude(String workspaceRelativePath) {
- PathFragment preludePathFragment = new PathFragment(workspaceRelativePath);
- Preconditions.checkArgument(!preludePathFragment.isAbsolute());
- Preconditions.checkArgument(preludePathFragment.isNormalized());
- this.preludePath = preludePathFragment;
+ public Builder setPrelude(String preludeLabelString) {
+ try {
+ this.preludeLabel = Label.parseAbsolute(preludeLabelString);
+ } catch (LabelSyntaxException e) {
+ String errorMsg =
+ String.format("Prelude label '%s' is not syntactically valid", preludeLabelString);
+ throw new IllegalArgumentException(errorMsg);
+ }
return this;
}
@@ -226,7 +228,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
}
return new ConfiguredRuleClassProvider(
- preludePath,
+ preludeLabel,
runfilesPrefix,
ImmutableMap.copyOf(ruleClassMap),
ImmutableMap.copyOf(ruleDefinitionMap),
@@ -269,9 +271,9 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
String defaultWorkspaceFile;
/**
- * Workspace-relative path to the prelude.
+ * Label for the prelude file.
*/
- private final PathFragment preludePath;
+ private final Label preludeLabel;
/**
* The default runfiles prefix.
@@ -315,7 +317,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
private final Environment.Frame globals;
public ConfiguredRuleClassProvider(
- PathFragment preludePath,
+ Label preludeLabel,
String runfilesPrefix,
ImmutableMap<String, RuleClass> ruleClassMap,
ImmutableMap<String, Class<? extends RuleDefinition>> ruleDefinitionMap,
@@ -327,7 +329,7 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
ConfigurationCollectionFactory configurationCollectionFactory,
PrerequisiteValidator prerequisiteValidator,
ImmutableMap<String, SkylarkType> skylarkAccessibleJavaClasses) {
- this.preludePath = preludePath;
+ this.preludeLabel = preludeLabel;
this.runfilesPrefix = runfilesPrefix;
this.ruleClassMap = ruleClassMap;
this.ruleDefinitionMap = ruleDefinitionMap;
@@ -346,8 +348,8 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
}
@Override
- public PathFragment getPreludePath() {
- return preludePath;
+ public Label getPreludeLabel() {
+ return preludeLabel;
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index 6151ee9fb4..df8d9c3236 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -227,7 +227,7 @@ public class BazelRuleClassProvider {
.addBuildInfoFactory(new CppBuildInfo())
.addBuildInfoFactory(new ObjcBuildInfoFactory())
.setConfigurationCollectionFactory(new BazelConfigurationCollection())
- .setPrelude("tools/build_rules/prelude_bazel")
+ .setPrelude("//tools/build_rules:prelude_bazel")
.setRunfilesPrefix("")
.setPrerequisiteValidator(new BazelPrerequisiteValidator());
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 e2ce1ba21f..170180e6e0 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
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.packages;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.Environment.Extension;
@@ -30,9 +31,9 @@ import javax.annotation.Nullable;
public interface RuleClassProvider {
/**
- * Workspace relative path to the prelude file.
+ * Label referencing the prelude file.
*/
- PathFragment getPreludePath();
+ Label getPreludeLabel();
/**
* The default runfiles prefix (may be overwritten by the WORKSPACE file).
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
index a7cd395b33..130386793e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java
@@ -14,10 +14,8 @@
package com.google.devtools.build.lib.skyframe;
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.RuleClassProvider;
-import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
import com.google.devtools.build.lib.syntax.BuildFileAST;
import com.google.devtools.build.lib.syntax.Mutability;
import com.google.devtools.build.lib.syntax.Runtime;
@@ -32,167 +30,95 @@ import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
/**
- * A SkyFunction for {@link ASTFileLookupValue}s. Tries to locate a file and load it as a
- * syntax tree and cache the resulting {@link BuildFileAST}. If the file doesn't exist
- * the function doesn't fail but returns a specific NO_FILE ASTLookupValue.
+ * A SkyFunction for {@link ASTFileLookupValue}s. Given a Label referencing a Skylark file,
+ * attempts to locate the file and load it as a syntax tree ({@link BuildFileAST}). If the file
+ * (or the package containing it) doesn't exist, the function doesn't fail, but instead returns a
+ * specific {@code NO_FILE} {@link ASTFileLookupValue}.
*/
public class ASTFileLookupFunction implements SkyFunction {
- private abstract static class FileLookupResult {
- /** Returns whether the file lookup was successful. */
- public abstract boolean lookupSuccessful();
-
- /** If {@code lookupSuccessful()}, returns the {@link RootedPath} to the file. */
- public abstract RootedPath rootedPath();
-
- /** If {@code lookupSuccessful()}, returns the file's size, in bytes. */
- public abstract long fileSize();
-
- static FileLookupResult noFile() {
- return UnsuccessfulFileResult.INSTANCE;
- }
-
- static FileLookupResult file(RootedPath rootedPath, long fileSize) {
- return new SuccessfulFileResult(rootedPath, fileSize);
- }
-
- private static class SuccessfulFileResult extends FileLookupResult {
- private final RootedPath rootedPath;
- private final long fileSize;
-
- private SuccessfulFileResult(RootedPath rootedPath, long fileSize) {
- this.rootedPath = rootedPath;
- this.fileSize = fileSize;
- }
-
- @Override
- public boolean lookupSuccessful() {
- return true;
- }
-
- @Override
- public RootedPath rootedPath() {
- return rootedPath;
- }
-
- @Override
- public long fileSize() {
- return fileSize;
- }
- }
-
- private static class UnsuccessfulFileResult extends FileLookupResult {
- private static final UnsuccessfulFileResult INSTANCE = new UnsuccessfulFileResult();
- private UnsuccessfulFileResult() {
- }
-
- @Override
- public boolean lookupSuccessful() {
- return false;
- }
-
- @Override
- public RootedPath rootedPath() {
- throw new IllegalStateException("unsuccessful lookup");
- }
-
- @Override
- public long fileSize() {
- throw new IllegalStateException("unsuccessful lookup");
- }
- }
- }
-
- private final AtomicReference<PathPackageLocator> pkgLocator;
private final RuleClassProvider ruleClassProvider;
- public ASTFileLookupFunction(AtomicReference<PathPackageLocator> pkgLocator,
- RuleClassProvider ruleClassProvider) {
- this.pkgLocator = pkgLocator;
+ public ASTFileLookupFunction(RuleClassProvider ruleClassProvider) {
this.ruleClassProvider = ruleClassProvider;
}
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException,
InterruptedException {
- PackageIdentifier key = (PackageIdentifier) skyKey.argument();
- PathFragment astFilePathFragment = key.getPackageFragment();
- FileLookupResult lookupResult = getASTFile(env, key);
- if (lookupResult == null) {
+ Label fileLabel = (Label) skyKey.argument();
+ PathFragment filePathFragment = fileLabel.toPathFragment();
+
+ /*
+ * Determine whether the package designated by fileLabel exists.
+ */
+ SkyKey pkgSkyKey = PackageLookupValue.key(fileLabel.getPackageIdentifier());
+ PackageLookupValue pkgLookupValue = null;
+ pkgLookupValue = (PackageLookupValue) env.getValue(pkgSkyKey);
+ if (pkgLookupValue == null) {
return null;
}
- if (!lookupResult.lookupSuccessful()) {
- return ASTFileLookupValue.noFile();
+ if (!pkgLookupValue.packageExists()) {
+ return ASTFileLookupValue.forBadPackage(fileLabel, pkgLookupValue.getErrorMsg());
}
+
+ /*
+ * Determine whether the file designated by fileLabel exists.
+ */
+ Path packageRoot = pkgLookupValue.getRoot();
+ RootedPath rootedPath = RootedPath.toRootedPath(packageRoot, filePathFragment);
+ SkyKey fileSkyKey = FileValue.key(rootedPath);
+ FileValue fileValue = null;
+ try {
+ fileValue = (FileValue) env.getValueOrThrow(fileSkyKey, IOException.class,
+ FileSymlinkException.class, InconsistentFilesystemException.class);
+ } catch (IOException | FileSymlinkException e) {
+ throw new ASTLookupFunctionException(new ErrorReadingSkylarkExtensionException(
+ e.getMessage()), Transience.PERSISTENT);
+ } catch (InconsistentFilesystemException e) {
+ throw new ASTLookupFunctionException(e, Transience.PERSISTENT);
+ }
+ if (fileValue == null) {
+ return null;
+ }
+ if (!fileValue.isFile()) {
+ return ASTFileLookupValue.forBadFile(fileLabel);
+ }
+
+ /*
+ * Both the package and the file exist; load the file and parse it as an AST.
+ */
BuildFileAST ast = null;
- Path path = lookupResult.rootedPath().asPath();
- long fileSize = lookupResult.fileSize();
- // Skylark files end with bzl.
- boolean parseAsSkylark = astFilePathFragment.getPathString().endsWith(".bzl");
+ Path path = rootedPath.asPath();
+ // Skylark files end with bzl
+ boolean parseAsSkylark = filePathFragment.getPathString().endsWith(".bzl");
try {
+ long astFileSize = fileValue.getSize();
if (parseAsSkylark) {
try (Mutability mutability = Mutability.create("validate")) {
- ast = BuildFileAST.parseSkylarkFile(path, fileSize, env.getListener(),
- new ValidationEnvironment(
- ruleClassProvider.createSkylarkRuleClassEnvironment(
- mutability,
- env.getListener(),
- // the two below don't matter for extracting the ValidationEnvironment:
- /*astFileContentHashCode=*/null,
- /*importMap=*/null)
- .setupDynamic(Runtime.PKG_NAME, Runtime.NONE)));
+ ast = BuildFileAST.parseSkylarkFile(path, astFileSize, env.getListener(),
+ new ValidationEnvironment(
+ ruleClassProvider.createSkylarkRuleClassEnvironment(
+ mutability,
+ env.getListener(),
+ // the two below don't matter for extracting the ValidationEnvironment:
+ /*astFileContentHashCode=*/null,
+ /*importMap=*/null)
+ .setupDynamic(Runtime.PKG_NAME, Runtime.NONE)));
}
} else {
- ast = BuildFileAST.parseBuildFile(path, fileSize, env.getListener(), false);
+ ast = BuildFileAST.parseBuildFile(path, astFileSize, env.getListener(), false);
}
} catch (IOException e) {
- throw new ASTLookupFunctionException(new ErrorReadingSkylarkExtensionException(
- e.getMessage()), Transience.TRANSIENT);
- }
- return ASTFileLookupValue.withFile(ast);
- }
-
- private FileLookupResult getASTFile(Environment env, PackageIdentifier key)
- throws ASTLookupFunctionException {
- List<Path> candidateRoots;
- if (!key.getRepository().isDefault()) {
- RepositoryValue repository =
- (RepositoryValue) env.getValue(RepositoryValue.key(key.getRepository()));
- if (repository == null) {
- return null;
- }
-
- candidateRoots = ImmutableList.of(repository.getPath());
- } else {
- candidateRoots = pkgLocator.get().getPathEntries();
+ throw new ASTLookupFunctionException(new ErrorReadingSkylarkExtensionException(
+ e.getMessage()), Transience.TRANSIENT);
}
- for (Path root : candidateRoots) {
- RootedPath rootedPath = RootedPath.toRootedPath(root, key.getPackageFragment());
- FileValue fileValue;
- try {
- fileValue = (FileValue) env.getValueOrThrow(FileValue.key(rootedPath),
- IOException.class, FileSymlinkException.class, InconsistentFilesystemException.class);
- } catch (IOException | FileSymlinkException e) {
- throw new ASTLookupFunctionException(new ErrorReadingSkylarkExtensionException(
- e.getMessage()), Transience.PERSISTENT);
- } catch (InconsistentFilesystemException e) {
- throw new ASTLookupFunctionException(e, Transience.PERSISTENT);
- }
- if (fileValue == null) {
- return null;
- }
- if (fileValue.isFile()) {
- return FileLookupResult.file(rootedPath, fileValue.getSize());
- }
- }
- return FileLookupResult.noFile();
+ return ASTFileLookupValue.withFile(ast);
}
@Nullable
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupValue.java
index 65fa3f0a96..29cc2e8f8a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupValue.java
@@ -14,48 +14,90 @@
package com.google.devtools.build.lib.skyframe;
-import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.common.base.Preconditions;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.syntax.BuildFileAST;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
-import javax.annotation.Nullable;
-
/**
- * A value that represents an AST file lookup result.
+ * A value that represents an AST file lookup result. There are two subclasses: one for the
+ * case where the file is found, and another for the case where the file is missing (but there
+ * are no other errors).
*/
-public class ASTFileLookupValue implements SkyValue {
+public abstract class ASTFileLookupValue implements SkyValue {
+ public abstract boolean lookupSuccessful();
+ public abstract BuildFileAST getAST();
+ public abstract String getErrorMsg();
+
+ /*
+ * If the file is found, this class encapsulates the parsed AST.
+ */
+ private static class ASTLookupWithFile extends ASTFileLookupValue {
+ private final BuildFileAST ast;
- private static final ASTFileLookupValue NO_FILE = new ASTFileLookupValue(null);
+ private ASTLookupWithFile(BuildFileAST ast) {
+ Preconditions.checkNotNull(ast);
+ this.ast = ast;
+ }
- @Nullable private final BuildFileAST ast;
+ @Override
+ public boolean lookupSuccessful() {
+ return true;
+ }
- private ASTFileLookupValue(@Nullable BuildFileAST ast) {
- this.ast = ast;
- }
+ @Override
+ public BuildFileAST getAST() {
+ return this.ast;
+ }
- public static ASTFileLookupValue noFile() {
- return NO_FILE;
+ @Override
+ public String getErrorMsg() {
+ throw new IllegalStateException("can't retrieve error for successful lookup");
+ }
}
+
+ /*
+ * If the file isn't found, this class encapsulates a message with the reason.
+ */
+ private static class ASTLookupNoFile extends ASTFileLookupValue {
+ private final String errorMsg;
- public static ASTFileLookupValue withFile(BuildFileAST ast) {
- return new ASTFileLookupValue(ast);
- }
+ private ASTLookupNoFile(String errorMsg) {
+ this.errorMsg = Preconditions.checkNotNull(errorMsg);
+ }
- /**
- * Returns the original AST file.
- */
- @Nullable public BuildFileAST getAST() {
- return ast;
+ @Override
+ public boolean lookupSuccessful() {
+ return false;
+ }
+
+ @Override
+ public BuildFileAST getAST() {
+ throw new IllegalStateException("can't retrieve AST for unsuccessful lookup");
+ }
+
+ @Override
+ public String getErrorMsg() {
+ return this.errorMsg;
+ }
}
- static SkyKey key(PackageIdentifier astFileIdentifier) {
- return new SkyKey(SkyFunctions.AST_FILE_LOOKUP, astFileIdentifier);
+ static ASTFileLookupValue forBadPackage(Label fileLabel, String reason) {
+ return new ASTLookupNoFile(
+ String.format("Unable to load package for '%s': %s", fileLabel, reason));
+ }
+
+ static ASTFileLookupValue forBadFile(Label fileLabel) {
+ return new ASTLookupNoFile(
+ String.format("Unable to load file '%s': file doesn't exist or isn't a file", fileLabel));
+ }
+
+ public static ASTFileLookupValue withFile(BuildFileAST ast) {
+ return new ASTLookupWithFile(ast);
}
- static final class ASTLookupInputException extends Exception {
- ASTLookupInputException(String msg) {
- super(msg);
- }
+ static SkyKey key(Label astFileLabel) {
+ return new SkyKey(SkyFunctions.AST_FILE_LOOKUP, astFileLabel);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
index 5e461fb113..10d06c493b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
@@ -15,6 +15,7 @@ package com.google.devtools.build.lib.skyframe;
import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
+import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -22,8 +23,8 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Location;
@@ -42,12 +43,12 @@ import com.google.devtools.build.lib.packages.RuleVisibility;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.profiler.Profiler;
import com.google.devtools.build.lib.profiler.ProfilerTask;
-import com.google.devtools.build.lib.skyframe.ASTFileLookupValue.ASTLookupInputException;
import com.google.devtools.build.lib.skyframe.GlobValue.InvalidGlobPatternException;
import com.google.devtools.build.lib.skyframe.SkylarkImportLookupFunction.SkylarkImportFailedException;
import com.google.devtools.build.lib.syntax.BuildFileAST;
import com.google.devtools.build.lib.syntax.Environment.Extension;
import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.LoadStatement;
import com.google.devtools.build.lib.syntax.ParserInputSource;
import com.google.devtools.build.lib.syntax.Statement;
import com.google.devtools.build.lib.util.Pair;
@@ -87,8 +88,7 @@ public class PackageFunction implements SkyFunction {
private final AtomicBoolean showLoadingProgress;
private final AtomicInteger numPackagesLoaded;
private final Profiler profiler = Profiler.instance();
-
- private final PathFragment preludePath;
+ private final Label preludeLabel;
static final String DEFAULTS_PACKAGE_NAME = "tools/defaults";
public static final String EXTERNAL_PACKAGE_NAME = "external";
@@ -101,9 +101,9 @@ public class PackageFunction implements SkyFunction {
this.reporter = reporter;
// Can be null in tests.
- this.preludePath = packageFactory == null
+ this.preludeLabel = packageFactory == null
? null
- : packageFactory.getRuleClassProvider().getPreludePath();
+ : packageFactory.getRuleClassProvider().getPreludeLabel();
this.packageFactory = packageFactory;
this.packageLocator = pkgLocator;
this.showLoadingProgress = showLoadingProgress;
@@ -432,21 +432,21 @@ public class PackageFunction implements SkyFunction {
return null;
}
+ SkyKey astLookupKey = ASTFileLookupValue.key(preludeLabel);
ASTFileLookupValue astLookupValue = null;
- SkyKey astLookupKey = ASTFileLookupValue.key(
- PackageIdentifier.createInDefaultRepo(preludePath));
try {
astLookupValue = (ASTFileLookupValue) env.getValueOrThrow(astLookupKey,
ErrorReadingSkylarkExtensionException.class, InconsistentFilesystemException.class);
} catch (ErrorReadingSkylarkExtensionException | InconsistentFilesystemException e) {
- throw new PackageFunctionException(new BadPreludeFileException(packageId, e.getMessage()),
- Transience.PERSISTENT);
+ throw new PackageFunctionException(
+ new BadPreludeFileException(packageId, e.getMessage()), Transience.PERSISTENT);
}
if (astLookupValue == null) {
return null;
}
- List<Statement> preludeStatements = astLookupValue.getAST() == null
- ? ImmutableList.<Statement>of() : astLookupValue.getAST().getStatements();
+ List<Statement> preludeStatements =
+ astLookupValue.lookupSuccessful()
+ ? astLookupValue.getAST().getStatements() : ImmutableList.<Statement>of();
// Load the BUILD file AST and handle Skylark dependencies. This way BUILD files are
// only loaded twice if there are unavailable Skylark or package dependencies or an
@@ -473,7 +473,6 @@ public class PackageFunction implements SkyFunction {
replacementContents,
packageId,
buildFilePath,
- buildFileFragment,
defaultVisibility,
preludeStatements,
env);
@@ -527,7 +526,6 @@ public class PackageFunction implements SkyFunction {
@Nullable
private SkylarkImportResult discoverSkylarkImports(
Path buildFilePath,
- PathFragment buildFileFragment,
PackageIdentifier packageId,
Environment env,
ParserInputSource inputSource,
@@ -547,8 +545,7 @@ public class PackageFunction implements SkyFunction {
ImmutableMap.<PathFragment, Extension>of(),
ImmutableList.<Label>of());
} else {
- importResult =
- fetchImportsFromBuildFile(buildFilePath, buildFileFragment, packageId, buildFileAST, env);
+ importResult = fetchImportsFromBuildFile(buildFilePath, packageId, buildFileAST, env);
}
return importResult;
@@ -561,33 +558,33 @@ public class PackageFunction implements SkyFunction {
@Nullable
private SkylarkImportResult fetchImportsFromBuildFile(
Path buildFilePath,
- PathFragment buildFileFragment,
PackageIdentifier packageId,
BuildFileAST buildFileAST,
Environment env)
throws PackageFunctionException {
- ImmutableMap<Location, PathFragment> imports = buildFileAST.getImports();
+ ImmutableCollection<LoadStatement> imports = buildFileAST.getImports();
Map<PathFragment, Extension> importMap = new HashMap<>();
ImmutableList.Builder<SkylarkFileDependency> fileDependencies = ImmutableList.builder();
+ Label buildFileLabel;
+ try {
+ buildFileLabel = Label.create(packageId, "BUILD");
+ } catch (LabelSyntaxException e) {
+ // Shouldn't happen; the Label is well-formed by construction.
+ throw new IllegalStateException(e);
+ }
try {
- for (Map.Entry<Location, PathFragment> entry : imports.entrySet()) {
- PathFragment importFile = entry.getValue();
- // HACK: The prelude sometimes contains load() statements, which need to be resolved
- // relative to the prelude file. However, we don't have a good way to tell "this should come
- // from the main repository" in a load() statement, and we don't have a good way to tell if
- // a load() statement comes from the prelude, since we just prepend those statements before
- // the actual BUILD file. So we use this evil .endsWith() statement to figure it out.
- RepositoryName repository =
- entry.getKey().getPath().endsWith(preludePath)
- ? PackageIdentifier.DEFAULT_REPOSITORY_NAME : packageId.getRepository();
- SkyKey importsLookupKey = SkylarkImportLookupValue.key(
- repository, buildFileFragment, importFile);
- SkylarkImportLookupValue importLookupValue = (SkylarkImportLookupValue)
- env.getValueOrThrow(importsLookupKey, SkylarkImportFailedException.class,
- InconsistentFilesystemException.class, ASTLookupInputException.class,
- BuildFileNotFoundException.class);
+ for (LoadStatement loadStmt : imports) {
+ Label importLabel =
+ SkylarkImportLookupFunction.findLabelForLoadStatement(loadStmt, buildFileLabel, env);
+ if (importLabel == null) {
+ return null;
+ }
+ SkyKey importsLookupKey = SkylarkImportLookupValue.key(importLabel);
+ SkylarkImportLookupValue importLookupValue = (SkylarkImportLookupValue) env.getValueOrThrow(
+ importsLookupKey, SkylarkImportFailedException.class,
+ InconsistentFilesystemException.class, BuildFileNotFoundException.class);
if (importLookupValue != null) {
- importMap.put(importFile, importLookupValue.getEnvironmentExtension());
+ importMap.put(loadStmt.getImportPath(), importLookupValue.getEnvironmentExtension());
fileDependencies.add(importLookupValue.getDependency());
}
}
@@ -598,10 +595,6 @@ public class PackageFunction implements SkyFunction {
} catch (InconsistentFilesystemException e) {
throw new PackageFunctionException(
new InternalInconsistentFilesystemException(packageId, e), Transience.PERSISTENT);
- } catch (ASTLookupInputException e) {
- // The load syntax is bad in the BUILD file so BuildFileContainsErrorsException is OK.
- throw new PackageFunctionException(
- new BuildFileContainsErrorsException(packageId, e.getMessage()), Transience.PERSISTENT);
} catch (BuildFileNotFoundException e) {
throw new PackageFunctionException(e, Transience.PERSISTENT);
}
@@ -770,7 +763,6 @@ public class PackageFunction implements SkyFunction {
@Nullable String replacementContents,
PackageIdentifier packageId,
Path buildFilePath,
- PathFragment buildFileFragment,
RuleVisibility defaultVisibility,
List<Statement> preludeStatements,
Environment env)
@@ -807,7 +799,6 @@ public class PackageFunction implements SkyFunction {
SkylarkImportResult importResult =
discoverSkylarkImports(
buildFilePath,
- buildFileFragment,
packageId,
env,
preprocessingResult.result,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 443a444452..ced28051e3 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -312,7 +312,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory {
map.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction());
map.put(SkyFunctions.PACKAGE_LOOKUP, new PackageLookupFunction(deletedPackages));
map.put(SkyFunctions.CONTAINING_PACKAGE_LOOKUP, new ContainingPackageLookupFunction());
- map.put(SkyFunctions.AST_FILE_LOOKUP, new ASTFileLookupFunction(pkgLocator, ruleClassProvider));
+ map.put(SkyFunctions.AST_FILE_LOOKUP, new ASTFileLookupFunction(ruleClassProvider));
map.put(SkyFunctions.SKYLARK_IMPORTS_LOOKUP, new SkylarkImportLookupFunction(
ruleClassProvider, pkgFactory));
map.put(SkyFunctions.GLOB, newGlobFunction());
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
index 29318f359c..d9180038eb 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupFunction.java
@@ -17,17 +17,15 @@ import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
import com.google.devtools.build.lib.packages.PackageFactory;
import com.google.devtools.build.lib.packages.RuleClassProvider;
import com.google.devtools.build.lib.rules.SkylarkRuleClassFunctions;
-import com.google.devtools.build.lib.skyframe.ASTFileLookupValue.ASTLookupInputException;
import com.google.devtools.build.lib.syntax.BuildFileAST;
import com.google.devtools.build.lib.syntax.Environment.Extension;
+import com.google.devtools.build.lib.syntax.LoadStatement;
import com.google.devtools.build.lib.syntax.Mutability;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
@@ -39,6 +37,8 @@ import com.google.devtools.build.skyframe.SkyValue;
import java.util.HashMap;
import java.util.Map;
+import javax.annotation.Nullable;
+
/**
* A Skyframe function to look up and import a single Skylark extension.
*/
@@ -56,111 +56,117 @@ public class SkylarkImportLookupFunction implements SkyFunction {
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException,
InterruptedException {
- PackageIdentifier arg = (PackageIdentifier) skyKey.argument();
- PathFragment file = arg.getPackageFragment();
+ Label fileLabel = (Label) skyKey.argument();
+ PathFragment importPath = fileLabel.toPathFragment();
ASTFileLookupValue astLookupValue = null;
try {
- SkyKey astLookupKey = ASTFileLookupValue.key(arg);
+ SkyKey astLookupKey = ASTFileLookupValue.key(fileLabel);
astLookupValue = (ASTFileLookupValue) env.getValueOrThrow(astLookupKey,
ErrorReadingSkylarkExtensionException.class, InconsistentFilesystemException.class);
} catch (ErrorReadingSkylarkExtensionException e) {
throw new SkylarkImportLookupFunctionException(SkylarkImportFailedException.errorReadingFile(
- file, e.getMessage()));
+ importPath, e.getMessage()));
} catch (InconsistentFilesystemException e) {
throw new SkylarkImportLookupFunctionException(e, Transience.PERSISTENT);
}
if (astLookupValue == null) {
return null;
}
- if (astLookupValue.getAST() == null) {
+ if (!astLookupValue.lookupSuccessful()) {
// Skylark import files have to exist.
- throw new SkylarkImportLookupFunctionException(SkylarkImportFailedException.noFile(file));
+ throw new SkylarkImportLookupFunctionException(
+ SkylarkImportFailedException.noFile(astLookupValue.getErrorMsg()));
}
Map<PathFragment, Extension> importMap = new HashMap<>();
ImmutableList.Builder<SkylarkFileDependency> fileDependencies = ImmutableList.builder();
BuildFileAST ast = astLookupValue.getAST();
- // TODO(bazel-team): Refactor this code and PackageFunction to reduce code duplications.
- for (Map.Entry<Location, PathFragment> entry : ast.getImports().entrySet()) {
+ for (LoadStatement loadStmt : ast.getImports()) {
try {
- PathFragment importFile = entry.getValue();
- // HACK: The prelude sometimes contains load() statements, which need to be resolved
- // relative to the prelude file. However, we don't have a good way to tell "this should come
- // from the main repository" in a load() statement, and we don't have a good way to tell if
- // a load() statement comes from the prelude, since we just prepend those statements before
- // the actual BUILD file. So we use this evil .endsWith() statement to figure it out.
- RepositoryName repository =
- entry.getKey().getPath().endsWith(ruleClassProvider.getPreludePath())
- ? PackageIdentifier.DEFAULT_REPOSITORY_NAME : arg.getRepository();
- SkyKey importsLookupKey = SkylarkImportLookupValue.key(repository, file, importFile);
+ Label importLabel = findLabelForLoadStatement(loadStmt, fileLabel, env);
+ if (importLabel == null) {
+ return null;
+ }
+ SkyKey importsLookupKey = SkylarkImportLookupValue.key(importLabel);
SkylarkImportLookupValue importsLookupValue;
- importsLookupValue = (SkylarkImportLookupValue) env.getValueOrThrow(
- importsLookupKey, ASTLookupInputException.class);
+ importsLookupValue = (SkylarkImportLookupValue) env.getValue(importsLookupKey);
if (importsLookupValue != null) {
- importMap.put(importFile, importsLookupValue.getEnvironmentExtension());
+ importMap.put(loadStmt.getImportPath(), importsLookupValue.getEnvironmentExtension());
fileDependencies.add(importsLookupValue.getDependency());
}
- } catch (ASTLookupInputException e) {
- throw new SkylarkImportLookupFunctionException(e, Transience.PERSISTENT);
+ } catch (SkylarkImportFailedException e) {
+ throw new SkylarkImportLookupFunctionException(e);
}
}
- Label label = pathFragmentToLabel(arg.getRepository(), file, env);
if (env.valuesMissing()) {
// This means some imports are unavailable.
return null;
}
if (ast.containsErrors()) {
- throw new SkylarkImportLookupFunctionException(SkylarkImportFailedException.skylarkErrors(
- file));
+ throw new SkylarkImportLookupFunctionException(
+ SkylarkImportFailedException.skylarkErrors(importPath));
}
// Skylark UserDefinedFunction-s in that file will share this function definition Environment,
// which will be frozen by the time it is returned by createExtension.
Extension extension =
- createExtension(ast, file, importMap, env);
+ createExtension(ast, importPath, importMap, env);
return new SkylarkImportLookupValue(
- extension, new SkylarkFileDependency(label, fileDependencies.build()));
+ extension, new SkylarkFileDependency(fileLabel, fileDependencies.build()));
}
- /**
- * Converts the PathFragment of the Skylark file to a Label using the BUILD file closest to the
- * Skylark file in its directory hierarchy - finds the package to which the Skylark file belongs.
- * Throws an exception if no such BUILD file exists.
- */
- private Label pathFragmentToLabel(RepositoryName repo, PathFragment file, Environment env)
- throws SkylarkImportLookupFunctionException {
- ContainingPackageLookupValue containingPackageLookupValue = null;
- try {
- PackageIdentifier newPkgId = new PackageIdentifier(repo, file.getParentDirectory());
- containingPackageLookupValue = (ContainingPackageLookupValue) env.getValueOrThrow(
- ContainingPackageLookupValue.key(newPkgId),
- BuildFileNotFoundException.class, InconsistentFilesystemException.class);
- } catch (BuildFileNotFoundException e) {
- // Thrown when there are IO errors looking for BUILD files.
- throw new SkylarkImportLookupFunctionException(e, Transience.PERSISTENT);
- } catch (InconsistentFilesystemException e) {
- throw new SkylarkImportLookupFunctionException(e, Transience.PERSISTENT);
- }
+ /**
+ * Given a Skylark {@link LoadStatement} and the {@link Label} of the file containing the load
+ * statement, returns a canonical {@link Label} corresponding to the load path in the statement.
+ * If no package can be found that contains the loaded file, throws
+ * {@link SkylarkImportFailedException}. Returns null if Skyframe dependencies are unavailable.
+ */
+ @Nullable
+ static Label findLabelForLoadStatement(LoadStatement loadStmt, Label containingFileLabel,
+ Environment env)
+ throws SkylarkImportFailedException {
+ PathFragment importPath = loadStmt.getImportPath();
+ PackageIdentifier pkgIdForImport;
+ String targetNameForImport;
+ if (loadStmt.isAbsolute()) {
+ PathFragment relativeImportPath = importPath.toRelative();
+ PackageIdentifier pkgToLookUp =
+ PackageIdentifier.createInDefaultRepo(relativeImportPath.getParentDirectory());
+ ContainingPackageLookupValue containingPackageLookupValue = null;
+ try {
+ containingPackageLookupValue = (ContainingPackageLookupValue) env.getValueOrThrow(
+ ContainingPackageLookupValue.key(pkgToLookUp),
+ BuildFileNotFoundException.class, InconsistentFilesystemException.class);
+ } catch (BuildFileNotFoundException e) {
+ // Thrown when there are IO errors looking for BUILD files.
+ throw new SkylarkImportFailedException(e);
+ } catch (InconsistentFilesystemException e) {
+ throw new SkylarkImportFailedException(e);
+ }
- if (containingPackageLookupValue == null) {
- return null;
- }
+ if (containingPackageLookupValue == null) {
+ return null;
+ }
- if (!containingPackageLookupValue.hasContainingPackage()) {
- throw new SkylarkImportLookupFunctionException(
- SkylarkImportFailedException.noBuildFile(file));
+ if (!containingPackageLookupValue.hasContainingPackage()) {
+ throw SkylarkImportFailedException.noBuildFile(importPath);
+ }
+ pkgIdForImport = containingPackageLookupValue.getContainingPackageName();
+ PathFragment containingPkgPath = pkgIdForImport.getPackageFragment();
+ targetNameForImport = relativeImportPath.relativeTo(containingPkgPath).toString();
+ } else {
+ // The load statement has a relative path
+ pkgIdForImport = containingFileLabel.getPackageIdentifier();
+ PathFragment containingDir =
+ (new PathFragment(containingFileLabel.getName())).getParentDirectory();
+ targetNameForImport = importPath.getRelative(containingDir).toString();
}
-
- PathFragment pkgName =
- containingPackageLookupValue.getContainingPackageName().getPackageFragment();
- PathFragment fileInPkg = file.relativeTo(pkgName);
-
try {
- // This code relies on PackageIdentifier.RepositoryName.toString()
- return Label.parseAbsolute(repo + "//" + pkgName.getPathString() + ":" + fileInPkg);
+ return Label.create(pkgIdForImport, targetNameForImport);
} catch (LabelSyntaxException e) {
+ // Shouldn't happen; the Label is well-formed by construction.
throw new IllegalStateException(e);
}
}
@@ -205,6 +211,14 @@ public class SkylarkImportLookupFunction implements SkyFunction {
super(errorMessage);
}
+ private SkylarkImportFailedException(InconsistentFilesystemException e) {
+ super(e.getMessage());
+ }
+
+ private SkylarkImportFailedException(BuildFileNotFoundException e) {
+ super(e.getMessage());
+ }
+
static SkylarkImportFailedException errors(PathFragment file) {
return new SkylarkImportFailedException(
String.format("Extension file '%s' has errors", file));
@@ -215,9 +229,9 @@ public class SkylarkImportLookupFunction implements SkyFunction {
String.format("Encountered error while reading extension file '%s': %s", file, error));
}
- static SkylarkImportFailedException noFile(PathFragment file) {
+ static SkylarkImportFailedException noFile(String reason) {
return new SkylarkImportFailedException(
- String.format("Extension file not found: '%s'", file));
+ String.format("Extension file not found. %s", reason));
}
static SkylarkImportFailedException noBuildFile(PathFragment file) {
@@ -242,11 +256,6 @@ public class SkylarkImportLookupFunction implements SkyFunction {
super(e, transience);
}
- private SkylarkImportLookupFunctionException(ASTLookupInputException e,
- Transience transience) {
- super(e, transience);
- }
-
private SkylarkImportLookupFunctionException(BuildFileNotFoundException e,
Transience transience) {
super(e, transience);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupValue.java
index 0ac9fd4402..e9d050d300 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkImportLookupValue.java
@@ -13,14 +13,9 @@
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
-import com.google.devtools.build.lib.cmdline.PackageIdentifier;
-import com.google.devtools.build.lib.cmdline.PackageIdentifier.RepositoryName;
-import com.google.devtools.build.lib.skyframe.ASTFileLookupValue.ASTLookupInputException;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.syntax.Environment.Extension;
-import com.google.devtools.build.lib.syntax.LoadStatement;
-import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
@@ -58,38 +53,7 @@ public class SkylarkImportLookupValue implements SkyValue {
return dependency;
}
- private static void checkInputArgument(PathFragment astFilePathFragment)
- throws ASTLookupInputException {
- if (astFilePathFragment.isAbsolute()) {
- throw new ASTLookupInputException(String.format(
- "Input file '%s' cannot be an absolute path.", astFilePathFragment));
- }
- }
-
- @VisibleForTesting
- static SkyKey key(PackageIdentifier pkgIdentifier) throws ASTLookupInputException {
- return key(pkgIdentifier.getRepository(), pkgIdentifier.getPackageFragment());
- }
-
- static SkyKey key(RepositoryName repo, PathFragment fromFile, PathFragment fileToImport)
- throws ASTLookupInputException {
- PathFragment computedPath;
- if (fileToImport.isAbsolute()) {
- computedPath = fileToImport.toRelative();
- } else if (fileToImport.segmentCount() == 1) {
- computedPath = fromFile.getParentDirectory().getRelative(fileToImport);
- } else {
- throw new ASTLookupInputException(String.format(LoadStatement.PATH_ERROR_MSG, fileToImport));
- }
- return key(repo, computedPath);
- }
-
- private static SkyKey key(RepositoryName repo, PathFragment fileToImport)
- throws ASTLookupInputException {
- // Skylark import lookup keys need to be valid AST file lookup keys.
- checkInputArgument(fileToImport);
- return new SkyKey(
- SkyFunctions.SKYLARK_IMPORTS_LOOKUP,
- new PackageIdentifier(repo, fileToImport));
+ static SkyKey key(Label importLabel) {
+ return new SkyKey(SkyFunctions.SKYLARK_IMPORTS_LOOKUP, importLabel);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java
index 5043879c80..902234ed3a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkylarkModuleCycleReporter.java
@@ -18,7 +18,7 @@ import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
-import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.skyframe.CycleInfo;
@@ -58,7 +58,7 @@ public class SkylarkModuleCycleReporter implements CyclesReporter.SingleCycleRep
new Function<SkyKey, String>() {
@Override
public String apply(SkyKey input) {
- return ((PackageIdentifier) input.argument()).toString();
+ return ((Label) input.argument()).toString();
}
});
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java b/src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java
index e6d00ef0bc..2faab99381 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BuildFileAST.java
@@ -14,13 +14,11 @@
package com.google.devtools.build.lib.syntax;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.hash.HashCode;
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.vfs.Path;
-import com.google.devtools.build.lib.vfs.PathFragment;
import java.io.IOException;
import java.util.List;
@@ -36,7 +34,7 @@ public class BuildFileAST extends ASTNode {
private final ImmutableList<Comment> comments;
- private ImmutableMap<Location, PathFragment> loads;
+ private ImmutableList<LoadStatement> loads;
/**
* Whether any errors were encountered during scanning or parsing.
@@ -61,13 +59,13 @@ public class BuildFileAST extends ASTNode {
setLocation(result.location);
}
- /** Collects paths from all load statements */
- private ImmutableMap<Location, PathFragment> fetchLoads(List<Statement> stmts) {
- ImmutableMap.Builder<Location, PathFragment> loads = ImmutableMap.builder();
+ /** Collects all load statements */
+ private ImmutableList<LoadStatement> fetchLoads(List<Statement> stmts) {
+ ImmutableList.Builder<LoadStatement> loads = new ImmutableList.Builder<>();
for (Statement stmt : stmts) {
if (stmt instanceof LoadStatement) {
LoadStatement imp = (LoadStatement) stmt;
- loads.put(imp.getLocation(), imp.getImportPath());
+ loads.add(imp);
}
}
return loads.build();
@@ -97,9 +95,9 @@ public class BuildFileAST extends ASTNode {
}
/**
- * Returns a set of loads in this BUILD file.
+ * Returns a list of loads in this BUILD file.
*/
- public synchronized ImmutableMap<Location, PathFragment> getImports() {
+ public synchronized ImmutableList<LoadStatement> getImports() {
if (loads == null) {
loads = fetchLoads(stmts);
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/LoadStatement.java b/src/main/java/com/google/devtools/build/lib/syntax/LoadStatement.java
index fc6fa77045..e4ede569d6 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/LoadStatement.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/LoadStatement.java
@@ -25,8 +25,6 @@ import java.util.Map;
*/
public final class LoadStatement extends Statement {
- public static final String PATH_ERROR_MSG = "Path '%s' is not valid. "
- + "It should either start with a slash or refer to a file in the current directory.";
private final ImmutableMap<Identifier, String> symbols;
private final ImmutableList<Identifier> cachedSymbols; // to save time
private final PathFragment importPath;
@@ -35,10 +33,9 @@ public final class LoadStatement extends Statement {
/**
* Constructs an import statement.
*
- * <p>Symbols maps a symbol to its original name under which it was defined in
- * the bzl file that should be loaded.
- * If aliasing is used, the value differs from it's key's symbol#getName().
- * Otherwise, both values are identical.
+ * <p>{@code symbols} maps a symbol to the original name under which it was defined in
+ * the bzl file that should be loaded. If aliasing is used, the value differs from its key's
+ * {@code symbol.getName()}. Otherwise, both values are identical.
*/
LoadStatement(StringLiteral path, Map<Identifier, String> symbols) {
this.symbols = ImmutableMap.copyOf(symbols);
@@ -71,7 +68,7 @@ public final class LoadStatement extends Statement {
getLocation(), "symbol '" + current + "' is private and cannot be imported");
}
// The key is the original name that was used to define the symbol
- // in the loaded bzl file
+ // in the loaded bzl file.
env.importSymbol(getImportPath(), current, entry.getValue());
} catch (Environment.NoSuchVariableException | Environment.LoadFailedException e) {
throw new EvalException(getLocation(), e.getMessage());
@@ -87,10 +84,6 @@ public final class LoadStatement extends Statement {
@Override
void validate(ValidationEnvironment env) throws EvalException {
validatePath();
-
- if (!importPath.isAbsolute() && importPath.segmentCount() > 1) {
- throw new EvalException(getLocation(), String.format(PATH_ERROR_MSG, importPath));
- }
for (Identifier symbol : cachedSymbols) {
env.declare(symbol.getName(), getLocation());
}
@@ -113,10 +106,19 @@ public final class LoadStatement extends Statement {
error =
"First argument of load() is a path, not a label. "
+ "It should start with a single slash if it is an absolute path.";
+ } else if (!importPath.isAbsolute() && importPath.segmentCount() > 1) {
+ error = String.format(
+ "Path '%s' is not valid. "
+ + "It should either start with a slash or refer to a file in the current directory.",
+ importPath);
}
if (error != null) {
throw new EvalException(getLocation(), error);
}
}
+
+ public boolean isAbsolute() {
+ return getImportPath().isAbsolute();
+ }
}
diff --git a/src/main/java/com/google/devtools/build/skyframe/SkyFunctionException.java b/src/main/java/com/google/devtools/build/skyframe/SkyFunctionException.java
index 09d2c4c49e..30d668ae82 100644
--- a/src/main/java/com/google/devtools/build/skyframe/SkyFunctionException.java
+++ b/src/main/java/com/google/devtools/build/skyframe/SkyFunctionException.java
@@ -22,7 +22,7 @@ import javax.annotation.Nullable;
* Base class of exceptions thrown by {@link SkyFunction#compute} on failure.
*
* SkyFunctions should declare a subclass {@code C} of {@link SkyFunctionException} whose
- * constructors forward fine-grained exception types (e.g. {@link IOException}) to
+ * constructors forward fine-grained exception types (e.g. {@code IOException}) to
* {@link SkyFunctionException}'s constructor, and they should also declare
* {@link SkyFunction#compute} to throw {@code C}. This way the type system checks that no
* unexpected exceptions are thrown by the {@link SkyFunction}.