diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
9 files changed, 227 insertions, 12 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryLoaderFunction.java b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryLoaderFunction.java index 2753346aac..a225672b61 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryLoaderFunction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/repository/RepositoryLoaderFunction.java @@ -18,6 +18,7 @@ import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.skyframe.ExternalPackageFunction; import com.google.devtools.build.lib.skyframe.PackageValue; import com.google.devtools.build.lib.skyframe.RepositoryValue; import com.google.devtools.build.lib.vfs.Path; @@ -48,7 +49,7 @@ public class RepositoryLoaderFunction implements SkyFunction { return null; } - SkyKey workspaceKey = PackageValue.workspaceKey( + SkyKey workspaceKey = ExternalPackageFunction.key( RootedPath.toRootedPath(repository.getPath(), new PathFragment("WORKSPACE"))); PackageValue workspacePackage = (PackageValue) env.getValue(workspaceKey); if (workspacePackage == null) { diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ExternalPackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ExternalPackageFunction.java new file mode 100644 index 0000000000..283e1a64ba --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ExternalPackageFunction.java @@ -0,0 +1,65 @@ +// Copyright 2016 The Bazel Authors. 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.skyframe; + +import com.google.devtools.build.lib.vfs.RootedPath; +import com.google.devtools.build.skyframe.SkyFunction; +import com.google.devtools.build.skyframe.SkyFunctionException; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; + +import javax.annotation.Nullable; + +/** + * A SkyFunction for resolving //external:* bindings. + * + * <p>This function iterates through the WorkspaceFileValue-s to get the last WorkspaceFileValue + * that will contains all the bind statements from the workspace file. + */ +public class ExternalPackageFunction implements SkyFunction { + + @Nullable + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws SkyFunctionException, InterruptedException { + RootedPath workspacePath = (RootedPath) skyKey.argument(); + SkyKey key = WorkspaceFileValue.key(workspacePath); + WorkspaceFileValue value = (WorkspaceFileValue) env.getValue(key); + if (value == null) { + return null; + } + // Walk to the last WorkspaceFileValue that accumulate all the bindings of the WORKSPACE + // file. + while (value.next() != null) { + value = (WorkspaceFileValue) env.getValue(value.next()); + if (value == null) { + return null; + } + } + return new PackageValue(value.getPackage()); + } + + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + + /** + * Returns a SkyKey to find the WORKSPACE file at the given path. + */ + public static SkyKey key(RootedPath workspacePath) { + return new SkyKey(SkyFunctions.EXTERNAL_PACKAGE, workspacePath); + } +} 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 d762190ca8..fc53e9ee22 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 @@ -340,7 +340,7 @@ public class PackageFunction implements SkyFunction { throws PackageFunctionException { RootedPath workspacePath = RootedPath.toRootedPath( packageLookupPath, new PathFragment("WORKSPACE")); - SkyKey workspaceKey = PackageValue.workspaceKey(workspacePath); + SkyKey workspaceKey = ExternalPackageFunction.key(workspacePath); PackageValue workspace = null; try { workspace = (PackageValue) env.getValueOrThrow(workspaceKey, IOException.class, diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageValue.java index 4e04eec827..01e4af54b4 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageValue.java @@ -19,7 +19,6 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.util.Preconditions; -import com.google.devtools.build.lib.vfs.RootedPath; import com.google.devtools.build.skyframe.NotComparableSkyValue; import com.google.devtools.build.skyframe.SkyKey; @@ -66,10 +65,4 @@ public class PackageValue implements NotComparableSkyValue { return keys; } - /** - * Returns a SkyKey to find the WORKSPACE file at the given path. - */ - public static SkyKey workspaceKey(RootedPath workspacePath) { - return new SkyKey(SkyFunctions.WORKSPACE_FILE, workspacePath); - } } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java index 0a04b8550c..3b393a9bac 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java @@ -238,7 +238,8 @@ public final class SequencedSkyframeExecutor extends SkyframeExecutor { SkyFunctions.DIRECTORY_LISTING_STATE, SkyFunctions.TARGET_PATTERN, SkyFunctions.PREPARE_DEPS_OF_PATTERN, - SkyFunctions.WORKSPACE_FILE); + SkyFunctions.WORKSPACE_FILE, + SkyFunctions.EXTERNAL_PACKAGE); @Override protected void onNewPackageLocator(PathPackageLocator oldLocator, PathPackageLocator pkgLocator) { diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java index ed3508f060..e6df1276e5 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java @@ -99,6 +99,7 @@ public final class SkyFunctions { public static final SkyFunctionName REPOSITORY_DIRECTORY = SkyFunctionName.create("REPOSITORY_DIRECTORY"); public static final SkyFunctionName WORKSPACE_AST = SkyFunctionName.create("WORKSPACE_AST"); + public static final SkyFunctionName EXTERNAL_PACKAGE = SkyFunctionName.create("EXTERNAL_PACKAGE"); public static Predicate<SkyKey> isSkyFunction(final SkyFunctionName functionName) { return new Predicate<SkyKey>() { 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 cd26d3f484..291730adba 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 @@ -385,6 +385,7 @@ public abstract class SkyframeExecutor implements WalkableGraphFactory { map.put( SkyFunctions.WORKSPACE_FILE, new WorkspaceFileFunction(ruleClassProvider, pkgFactory, directories)); + map.put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction()); map.put(SkyFunctions.TARGET_COMPLETION, CompletionFunction.targetCompletionFunction(eventBus)); map.put(SkyFunctions.ASPECT_COMPLETION, CompletionFunction.aspectCompletionFunction(eventBus)); map.put(SkyFunctions.TEST_COMPLETION, new TestCompletionFunction()); diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java index dc2b0c2979..fd948ee6f6 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileFunction.java @@ -21,6 +21,7 @@ import com.google.devtools.build.lib.packages.PackageFactory; import com.google.devtools.build.lib.packages.RuleClassProvider; import com.google.devtools.build.lib.packages.WorkspaceFactory; import com.google.devtools.build.lib.skyframe.PackageFunction.PackageFunctionException; +import com.google.devtools.build.lib.skyframe.WorkspaceFileValue.WorkspaceFileKey; import com.google.devtools.build.lib.syntax.BuildFileAST; import com.google.devtools.build.lib.syntax.Mutability; import com.google.devtools.build.lib.vfs.Path; @@ -53,7 +54,7 @@ public class WorkspaceFileFunction implements SkyFunction { public SkyValue compute(SkyKey skyKey, Environment env) throws WorkspaceFileFunctionException, InterruptedException { - RootedPath workspaceRoot = (RootedPath) skyKey.argument(); + RootedPath workspaceRoot = ((WorkspaceFileKey) skyKey.argument()).getPath(); WorkspaceASTValue workspaceASTValue = (WorkspaceASTValue) env.getValue(new SkyKey(SkyFunctions.WORKSPACE_AST, workspaceRoot)); if (workspaceASTValue == null) { @@ -88,7 +89,7 @@ public class WorkspaceFileFunction implements SkyFunction { } } - return new PackageValue(builder.build()); + return new WorkspaceFileValue(builder.build(), workspaceRoot, 0, false); } @Override diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileValue.java new file mode 100644 index 0000000000..877d7c5e33 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceFileValue.java @@ -0,0 +1,152 @@ +// Copyright 2016 The Bazel Authors. 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.skyframe; + +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; +import com.google.devtools.build.lib.packages.Package; +import com.google.devtools.build.lib.util.Preconditions; +import com.google.devtools.build.lib.vfs.RootedPath; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; + +import java.util.Objects; + +/** + * A SkyValue that contains the result of the parsing of one part of the WORKSPACE file. The parsing + * of the WORKSPACE file is split before each series of load statement because we need to resolve + * repositories before being able to load from those repositories. + */ +public class WorkspaceFileValue implements SkyValue { + + /** + * Argument for the SkyKey to request a WorkspaceFileValue. + */ + @Immutable + public static class WorkspaceFileKey { + private final RootedPath path; + private final int idx; + + /** + * Creates a Key for the WorkspaceFileFunction. The path to the workspace file is specified + * by {@code path}. This key will ask WorkspaceFileFunction to get the {@code idx+1}-th part of + * the workspace file (so idx = 0 represents the first part, idx = 1, the second part, etc...). + */ + public WorkspaceFileKey(RootedPath path, int idx) { + this.path = path; + this.idx = idx; + } + + public RootedPath getPath() { + return path; + } + + public int getIndex() { + return idx; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof WorkspaceFileKey)) { + return false; + } + WorkspaceFileKey other = (WorkspaceFileKey) obj; + return Objects.equals(path, other.path) && idx == other.idx; + } + + @Override + public int hashCode() { + return Objects.hash(path.hashCode(), idx); + } + + @Override + public String toString() { + return path + ", " + idx; + } + } + + private final Package pkg; + private final int idx; + private final RootedPath path; + private final boolean hasNext; + + public WorkspaceFileValue(Package pkg, RootedPath path, int idx, boolean hasNext) { + this.pkg = Preconditions.checkNotNull(pkg); + this.idx = idx; + this.path = path; + this.hasNext = hasNext; + } + + /** + * Returns the package. This package may contain errors, in which case the caller should throw + * a {@link BuildFileContainsErrorsException}. + */ + public Package getPackage() { + return pkg; + } + + @Override + public String toString() { + return "<WorkspaceFileValue idx=" + idx + ">"; + } + + private static SkyKey key(RootedPath path, int idx) { + return new SkyKey(SkyFunctions.WORKSPACE_FILE, new WorkspaceFileKey(path, idx)); + } + + public static SkyKey key(RootedPath path) { + return key(path, 0); + } + + /** + * Get the key for the next WorkspaceFileValue or null if this value is the last part of the + * workspace file. + */ + public SkyKey next() { + if (hasNext) { + return key(path, idx + 1); + } else { + return null; + } + } + + /** + * The workspace file parsing is cut in several parts and this function returns the index of the + * part of the workspace file that this value holds. For the first part, this index will be 0, for + * the second part, it will be 1 and so on. + */ + public int getIndex() { + return idx; + } + + /** + * The workspace file parsing is cut in several parts and this function returns true if there is + * a part following the part holds by this value (or false if this is the last part of the + * WORKSPACE file. + * + * <p>This method is public for serialization of the WorkspaceFileValue, #next() should be used + * to iterate instead of this method. + */ + public boolean hasNext() { + return hasNext; + } + + public RootedPath getPath() { + return path; + } +} |