Refactor `FlagSetFunction` to depend on a `ProjectValue` directly, instead of depending on its own `BzlLoadValue`. The dependency chain is now `FlagSetFunction` -> `ProjectFunction` -> `BzlLoadFunction`. `FlagSetFunction` is kept distinct from `ProjectFunction` so as to not burden other reverse dependencies of `ProjectFunction` from the extra Skyframe lookup costs from `FlagSetFunction` (i.e. `ParsedFlagsFunction`). `ProjectFunction` is implemented as an indirection to `BzlLoadValue`, so there's a place for PROJECT.scl specific validations and getters in the future. PiperOrigin-RevId: 641126914 Change-Id: I4e799395817c8d0f96a0af3e6c6520b29fafdf08
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD index 978c8f4..9929f02 100644 --- a/src/main/java/com/google/devtools/build/lib/BUILD +++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -432,7 +432,7 @@ "//src/main/java/com/google/devtools/build/lib/skyframe:package_roots_no_symlink_creation", "//src/main/java/com/google/devtools/build/lib/skyframe:package_value", "//src/main/java/com/google/devtools/build/lib/skyframe:precomputed_value", - "//src/main/java/com/google/devtools/build/lib/skyframe:project_owned_code_paths_value", + "//src/main/java/com/google/devtools/build/lib/skyframe:project_value", "//src/main/java/com/google/devtools/build/lib/skyframe:repository_mapping_value", "//src/main/java/com/google/devtools/build/lib/skyframe:sky_functions", "//src/main/java/com/google/devtools/build/lib/skyframe:skyfocus",
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java index f993501..c4915a6 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
@@ -66,7 +66,7 @@ import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code; import com.google.devtools.build.lib.server.FailureDetails.FailureDetail; import com.google.devtools.build.lib.skyframe.BuildResultListener; -import com.google.devtools.build.lib.skyframe.ProjectOwnedCodePathsValue; +import com.google.devtools.build.lib.skyframe.ProjectValue; import com.google.devtools.build.lib.skyframe.RepositoryMappingValue.RepositoryMappingResolutionException; import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutor; import com.google.devtools.build.lib.skyframe.SkyframeBuildView.BuildDriverKeyTestContext; @@ -816,7 +816,7 @@ private static ImmutableSet<PathFragment> getProjectDirectories( Label projectFile, SkyframeExecutor skyframeExecutor, ExtendedEventHandler eventHandler) throws InvalidConfigurationException { - ProjectOwnedCodePathsValue.Key key = new ProjectOwnedCodePathsValue.Key(projectFile); + ProjectValue.Key key = new ProjectValue.Key(projectFile); EvaluationResult<SkyValue> result = skyframeExecutor.evaluateSkyKeys( eventHandler, ImmutableList.of(key), /* keepGoing= */ false); @@ -829,7 +829,7 @@ Code.INVALID_PROJECT); } - return ((ProjectOwnedCodePathsValue) result.get(key)) + return ((ProjectValue) result.get(key)) .getOwnedCodePaths().stream().map(PathFragment::create).collect(toImmutableSet()); }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD index 4095a7a..5721ad6 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -167,7 +167,7 @@ ":prerequisite_package_function", ":progress_event_suppressing_environment", ":project_files_lookup_function", - ":project_owned_code_paths_function", + ":project_function", ":recursive_filesystem_traversal", ":recursive_package_provider_backed_target_pattern_resolver", ":recursive_pkg_function", @@ -1175,10 +1175,11 @@ ) java_library( - name = "project_owned_code_paths_function", - srcs = ["ProjectOwnedCodePathsFunction.java"], + name = "project_function", + srcs = ["ProjectFunction.java"], deps = [ - ":project_owned_code_paths_value", + ":project_value", + "//src/main/java/com/google/devtools/build/lib/skyframe:bzl_load_failed_exception", "//src/main/java/com/google/devtools/build/lib/skyframe:bzl_load_value", "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects", "//third_party:guava", @@ -1187,13 +1188,14 @@ ) java_library( - name = "project_owned_code_paths_value", - srcs = ["ProjectOwnedCodePathsValue.java"], + name = "project_value", + srcs = ["ProjectValue.java"], deps = [ ":sky_functions", "//src/main/java/com/google/devtools/build/lib/cmdline", "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects", "//third_party:guava", + "//third_party:jsr305", ], )
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ProjectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ProjectFunction.java new file mode 100644 index 0000000..8f63ab8 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ProjectFunction.java
@@ -0,0 +1,103 @@ +// Copyright 2024 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 static com.google.common.collect.ImmutableMap.toImmutableMap; +import static com.google.devtools.build.skyframe.SkyFunctionException.Transience.PERSISTENT; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +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 java.util.Collection; +import java.util.Map; +import javax.annotation.Nullable; + +/** A {@link SkyFunction} that loads metadata from a PROJECT.scl file. */ +public class ProjectFunction implements SkyFunction { + + private static final String OWNED_CODE_PATHS_KEY = "owned_code_paths"; + + // The set of top level reserved globals in the PROJECT.scl file. + private static final ImmutableSet<String> RESERVED_GLOBALS = + ImmutableSet.of(OWNED_CODE_PATHS_KEY); + + @Nullable + @Override + public SkyValue compute(SkyKey skyKey, Environment env) + throws ProjectFunctionException, InterruptedException { + ProjectValue.Key key = (ProjectValue.Key) skyKey.argument(); + + BzlLoadValue bzlLoadValue; + try { + bzlLoadValue = + (BzlLoadValue) + env.getValueOrThrow( + BzlLoadValue.keyForBuild(key.getProjectFile()), BzlLoadFailedException.class); + } catch (BzlLoadFailedException e) { + throw new ProjectFunctionException(e, PERSISTENT); + } + if (bzlLoadValue == null) { + return null; + } + + Object ownedCodePathsRaw = bzlLoadValue.getModule().getGlobal(OWNED_CODE_PATHS_KEY); + + // Crude typechecking to prevent server crashes. + @SuppressWarnings("unchecked") + Collection<? extends String> ownedCodePaths = + switch (ownedCodePathsRaw) { + case null -> ImmutableSet.of(); + case Collection<?> xs -> { + for (Object x : xs) { + if (!(x instanceof String)) { + throw new ProjectFunctionException( + new TypecheckFailureException( + "expected a list of strings, got element of " + x.getClass())); + } + } + yield (Collection<String>) xs; + } + default -> + throw new ProjectFunctionException( + new TypecheckFailureException( + "expected a list of strings, got " + ownedCodePathsRaw.getClass())); + }; + + ImmutableMap<String, Object> residualGlobals = + bzlLoadValue.getModule().getGlobals().entrySet().stream() + .filter(entry -> !RESERVED_GLOBALS.contains(entry.getKey())) + .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)); + + return new ProjectValue(ImmutableSet.copyOf(ownedCodePaths), residualGlobals); + } + + private static final class TypecheckFailureException extends Exception { + TypecheckFailureException(String msg) { + super(msg); + } + } + + private static final class ProjectFunctionException extends SkyFunctionException { + ProjectFunctionException(TypecheckFailureException cause) { + super(cause, PERSISTENT); + } + + ProjectFunctionException(BzlLoadFailedException e, Transience transience) { + super(e, transience); + } + } +}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ProjectOwnedCodePathsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ProjectOwnedCodePathsFunction.java deleted file mode 100644 index 33ed08c..0000000 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ProjectOwnedCodePathsFunction.java +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2024 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.common.collect.ImmutableSet; -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 java.util.Collection; -import javax.annotation.Nullable; - -/** A {@link SkyFunction} that loads the owned code paths from a project file. */ -public class ProjectOwnedCodePathsFunction implements SkyFunction { - - private static final String TOP_LEVEL_VARIABLE_NAME = "owned_code_paths"; - - @Nullable - @Override - public SkyValue compute(SkyKey skyKey, Environment env) - throws SkyFunctionException, InterruptedException { - ProjectOwnedCodePathsValue.Key key = (ProjectOwnedCodePathsValue.Key) skyKey.argument(); - - BzlLoadValue bzlLoadValue = - (BzlLoadValue) env.getValue(BzlLoadValue.keyForBuild(key.getProjectFile())); - if (bzlLoadValue == null) { - return null; - } - - Object ret = bzlLoadValue.getModule().getGlobal(TOP_LEVEL_VARIABLE_NAME); - if (ret == null) { - return new ProjectOwnedCodePathsValue(ImmutableSet.of()); - } else { - @SuppressWarnings("unchecked") - Collection<? extends String> dirs = (Collection<? extends String>) ret; - return new ProjectOwnedCodePathsValue(ImmutableSet.copyOf(dirs)); - } - } -}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ProjectOwnedCodePathsValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/ProjectOwnedCodePathsValue.java deleted file mode 100644 index 041d50b..0000000 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ProjectOwnedCodePathsValue.java +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2024 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.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; -import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.skyframe.SkyFunctionName; -import com.google.devtools.build.skyframe.SkyKey; -import com.google.devtools.build.skyframe.SkyValue; - -/** A SkyValue representing the code paths that are owned by a project. */ -public final class ProjectOwnedCodePathsValue implements SkyValue { - - private final ImmutableSet<String> ownedCodePaths; - - public ProjectOwnedCodePathsValue(ImmutableSet<String> ownedCodePaths) { - this.ownedCodePaths = ownedCodePaths; - } - - public ImmutableSet<String> getOwnedCodePaths() { - return ownedCodePaths; - } - - /** The SkyKey. Uses the label of the project file as the input. */ - public static final class Key implements SkyKey { - private final Label projectFile; - - public Key(Label projectFile) { - this.projectFile = Preconditions.checkNotNull(projectFile); - } - - public Label getProjectFile() { - return projectFile; - } - - @Override - public SkyFunctionName functionName() { - return SkyFunctions.PROJECT_DIRECTORIES; - } - } -}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ProjectValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/ProjectValue.java new file mode 100644 index 0000000..462d482 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ProjectValue.java
@@ -0,0 +1,92 @@ +// Copyright 2024 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.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.skyframe.SkyFunctionName; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; +import java.util.Objects; +import javax.annotation.Nullable; + +/** A SkyValue representing the parsed definitions from a PROJECT.scl file. */ +public final class ProjectValue implements SkyValue { + + private final ImmutableSet<String> ownedCodePaths; + + private final ImmutableMap<String, Object> residualGlobals; + + public ProjectValue( + ImmutableSet<String> ownedCodePaths, ImmutableMap<String, Object> residualGlobals) { + this.ownedCodePaths = ownedCodePaths; + this.residualGlobals = residualGlobals; + } + + /** + * Returns the residual global referenced by the {@code key} found in the PROJECT file. + * + * <p>This returns null for non-existent keys and reserved globals. Use the dedicated getters to + * access the reserved globals. See {@code ProjectFunction.RESERVED_GLOBALS} for the list. + */ + @Nullable + public Object getResidualGlobal(String key) { + return residualGlobals.get(key); + } + + /** + * Returns the list of code paths defined by the {@code ProjectFunction.OWNED_CODE_PATHS_KEY}. If + * the list is not defined in the file, returns an empty set. + */ + public ImmutableSet<String> getOwnedCodePaths() { + return ownedCodePaths; + } + + /** The SkyKey. Uses the label of the project file as the input. */ + public static final class Key implements SkyKey { + private final Label projectFile; + + public Key(Label projectFile) { + this.projectFile = Preconditions.checkNotNull(projectFile); + } + + public Label getProjectFile() { + return projectFile; + } + + @Override + public SkyFunctionName functionName() { + return SkyFunctions.PROJECT; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ProjectValue.Key key = (ProjectValue.Key) o; + return Objects.equals(projectFile, key.projectFile); + } + + @Override + public int hashCode() { + return Objects.hashCode(projectFile); + } + } +}
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 3b541aa..aa593e8 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
@@ -38,8 +38,7 @@ SkyFunctionName.createHermetic("PACKAGE_LOOKUP"); public static final SkyFunctionName CONTAINING_PACKAGE_LOOKUP = SkyFunctionName.createHermetic("CONTAINING_PACKAGE_LOOKUP"); - public static final SkyFunctionName PROJECT_DIRECTORIES = - SkyFunctionName.createHermetic("PROJECT_DIRECTORIES"); + public static final SkyFunctionName PROJECT = SkyFunctionName.createHermetic("PROJECT"); public static final SkyFunctionName PROJECT_FILES_LOOKUP = SkyFunctionName.createHermetic("PROJECT_FILES_LOOKUP"); public static final SkyFunctionName BZL_COMPILE = SkyFunctionName.createHermetic("BZL_COMPILE");
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 38892da..b3b45ff 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
@@ -635,7 +635,7 @@ buildFilesByPriority, externalPackageHelper)); map.put(SkyFunctions.CONTAINING_PACKAGE_LOOKUP, new ContainingPackageLookupFunction()); - map.put(SkyFunctions.PROJECT_DIRECTORIES, new ProjectOwnedCodePathsFunction()); + map.put(SkyFunctions.PROJECT, new ProjectFunction()); map.put(SkyFunctions.PROJECT_FILES_LOOKUP, new ProjectFilesLookupFunction()); map.put( SkyFunctions.BZL_COMPILE, // TODO rename
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/config/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/config/BUILD index 9e94bb2..9d0113a 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/config/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/config/BUILD
@@ -52,6 +52,7 @@ "//src/main/java/com/google/devtools/build/lib/skyframe:bzl_load_value", "//src/main/java/com/google/devtools/build/lib/skyframe:package_value", "//src/main/java/com/google/devtools/build/lib/skyframe:precomputed_value", + "//src/main/java/com/google/devtools/build/lib/skyframe:project_value", "//src/main/java/com/google/devtools/build/lib/skyframe:repository_mapping_value", "//src/main/java/com/google/devtools/build/lib/skyframe:workspace_name_value", "//src/main/java/com/google/devtools/build/lib/skyframe/toolchains:platform_lookup_util",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/config/FlagSetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/config/FlagSetFunction.java index 37a5ade..607108c 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/config/FlagSetFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/config/FlagSetFunction.java
@@ -13,17 +13,16 @@ // limitations under the License. package com.google.devtools.build.lib.skyframe.config; +import static com.google.devtools.build.lib.cmdline.RepositoryName.MAIN; + import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.BuildOptionsView; import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition; -import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.Label.RepoContext; -import com.google.devtools.build.lib.cmdline.RepositoryName; import com.google.devtools.build.lib.events.EventHandler; -import com.google.devtools.build.lib.skyframe.BzlLoadFailedException; -import com.google.devtools.build.lib.skyframe.BzlLoadValue; +import com.google.devtools.build.lib.skyframe.ProjectValue; import com.google.devtools.build.lib.skyframe.RepositoryMappingValue; import com.google.devtools.build.lib.skyframe.config.ParsedFlagsFunction.ParsedFlagsFunctionException; import com.google.devtools.build.skyframe.SkyFunction; @@ -60,25 +59,25 @@ return FlagSetValue.create(key.getTargetOptions()); } - BzlLoadValue sclLoadValue = loadSclFile(key.getProjectFile(), env); - - if (sclLoadValue == null) { + ProjectValue projectValue = + (ProjectValue) env.getValue(new ProjectValue.Key(key.getProjectFile())); + if (projectValue == null) { return null; } RepositoryMappingValue mainRepositoryMappingValue = - (RepositoryMappingValue) env.getValue(RepositoryMappingValue.key(RepositoryName.MAIN)); + (RepositoryMappingValue) env.getValue(RepositoryMappingValue.key(MAIN)); if (mainRepositoryMappingValue == null) { return null; } RepoContext mainRepoContext = - RepoContext.of(RepositoryName.MAIN, mainRepositoryMappingValue.getRepositoryMapping()); + RepoContext.of(MAIN, mainRepositoryMappingValue.getRepositoryMapping()); List<String> rawFlags = new ArrayList<>(); - if (sclLoadValue.getModule().getGlobal(key.getSclConfig()) != null) { + if (projectValue.getResidualGlobal(key.getSclConfig()) != null) { rawFlags.addAll( - (Collection<? extends String>) sclLoadValue.getModule().getGlobal(key.getSclConfig())); + (Collection<? extends String>) projectValue.getResidualGlobal(key.getSclConfig())); } else { return FlagSetValue.create(key.getTargetOptions()); } @@ -114,20 +113,6 @@ return FlagSetValue.create(adjustedBuildOptions); } - private BzlLoadValue loadSclFile(Label sclFileLabel, Environment env) - throws FlagSetFunctionException, InterruptedException { - BzlLoadValue bzlLoadValue; - try { - bzlLoadValue = - (BzlLoadValue) - env.getValueOrThrow( - BzlLoadValue.keyForBuild(sclFileLabel), BzlLoadFailedException.class); - } catch (BzlLoadFailedException e) { - throw new FlagSetFunctionException(e, Transience.PERSISTENT); - } - return bzlLoadValue; - } - private static final class FlagSetFunctionException extends SkyFunctionException { FlagSetFunctionException(Exception cause, Transience transience) { super(cause, transience);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/config/FlagSetValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/config/FlagSetValue.java index ae2a4c2..232c51c 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/config/FlagSetValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/config/FlagSetValue.java
@@ -33,7 +33,6 @@ @AutoCodec public static final class Key implements SkyKey { private static final SkyKeyInterner<Key> interner = SkyKey.newInterner(); - // private final String sclFile; private final Label projectFile; private final String sclConfig; private final BuildOptions targetOptions;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/BUILD b/src/test/java/com/google/devtools/build/lib/skyframe/BUILD index c8c3f0e..f803b79 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/BUILD +++ b/src/test/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -680,6 +680,21 @@ ) java_test( + name = "ProjectFunctionTest", + srcs = ["ProjectFunctionTest.java"], + deps = [ + ":testutil", + "//src/main/java/com/google/devtools/build/lib/cmdline", + "//src/main/java/com/google/devtools/build/lib/skyframe:project_value", + "//src/main/java/com/google/devtools/build/skyframe", + "//src/main/java/net/starlark/java/eval", + "//src/test/java/com/google/devtools/build/lib/analysis/util", + "//third_party:junit4", + "//third_party:truth", + ], +) + +java_test( name = "ActionExecutionValueTransformSharedTreeArtifactsTest", timeout = "short", srcs = ["ActionExecutionValueTransformSharedTreeArtifactsTest.java"],
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ProjectFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ProjectFunctionTest.java new file mode 100644 index 0000000..c68a7e2 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skyframe/ProjectFunctionTest.java
@@ -0,0 +1,139 @@ +// Copyright 2024 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 static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils; +import com.google.devtools.build.skyframe.EvaluationResult; +import java.util.Collection; +import net.starlark.java.eval.StarlarkInt; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ProjectFunctionTest extends BuildViewTestCase { + + @Before + public void setUp() throws Exception { + setBuildLanguageOptions("--experimental_enable_scl_dialect=true"); + } + + @Test + public void projectFunction_emptyFile_isValid() throws Exception { + scratch.file("test/PROJECT.scl", ""); + scratch.file("test/BUILD"); + ProjectValue.Key key = new ProjectValue.Key(Label.parseCanonical("//test:PROJECT.scl")); + + EvaluationResult<ProjectValue> result = + SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, false, reporter); + assertThat(result.hasError()).isFalse(); + + ProjectValue value = result.get(key); + assertThat(value.getOwnedCodePaths()).isEmpty(); + } + + @Test + public void projectFunction_returnsOwnedCodePaths() throws Exception { + scratch.file("test/PROJECT.scl", "owned_code_paths = ['a', 'b/c']"); + scratch.file("test/BUILD"); + ProjectValue.Key key = new ProjectValue.Key(Label.parseCanonical("//test:PROJECT.scl")); + + EvaluationResult<ProjectValue> result = + SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, false, reporter); + assertThat(result.hasError()).isFalse(); + + ProjectValue value = result.get(key); + assertThat(value.getOwnedCodePaths()).containsExactly("a", "b/c"); + } + + @Test + public void projectFunction_incorrectType() throws Exception { + scratch.file("test/PROJECT.scl", "owned_code_paths = 42"); + scratch.file("test/BUILD"); + ProjectValue.Key key = new ProjectValue.Key(Label.parseCanonical("//test:PROJECT.scl")); + + EvaluationResult<ProjectValue> result = + SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, false, reporter); + assertThat(result.hasError()).isTrue(); + assertThat(result.getError().getException()) + .hasMessageThat() + .matches("expected a list of strings, got .+Int32"); + } + + @Test + public void projectFunction_incorrectType_inList() throws Exception { + scratch.file("test/PROJECT.scl", "owned_code_paths = [42]"); + scratch.file("test/BUILD"); + ProjectValue.Key key = new ProjectValue.Key(Label.parseCanonical("//test:PROJECT.scl")); + + EvaluationResult<ProjectValue> result = + SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, false, reporter); + assertThat(result.hasError()).isTrue(); + assertThat(result.getError().getException()) + .hasMessageThat() + .matches("expected a list of strings, got element of .+Int32"); + } + + @Test + public void projectFunction_parsesResidualGlobals() throws Exception { + scratch.file( + "test/PROJECT.scl", + """ + owned_code_paths = ["a", "b/c"] + foo = [0, 1] + bar = 'str' + """); + scratch.file("test/BUILD"); + ProjectValue.Key key = new ProjectValue.Key(Label.parseCanonical("//test:PROJECT.scl")); + + EvaluationResult<ProjectValue> result = + SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, false, reporter); + assertThat(result.hasError()).isFalse(); + + ProjectValue value = result.get(key); + assertThat(value.getOwnedCodePaths()).containsExactly("a", "b/c"); + assertThat(value.getResidualGlobal("owned_code_paths")).isNull(); + assertThat(value.getResidualGlobal("nonexistent_global")).isNull(); + + @SuppressWarnings("unchecked") + Collection<StarlarkInt> fooValue = (Collection<StarlarkInt>) value.getResidualGlobal("foo"); + assertThat(fooValue).containsExactly(StarlarkInt.of(0), StarlarkInt.of(1)); + + String barValue = (String) value.getResidualGlobal("bar"); + assertThat(barValue).isEqualTo("str"); + } + + @Test + public void projectFunction_catchSyntaxError() throws Exception { + scratch.file( + "test/PROJECT.scl", + """ + something_is_wrong = + """); + scratch.file("test/BUILD"); + ProjectValue.Key key = new ProjectValue.Key(Label.parseCanonical("//test:PROJECT.scl")); + + AssertionError e = + assertThrows( + AssertionError.class, + () -> SkyframeExecutorTestUtils.evaluate(skyframeExecutor, key, false, reporter)); + assertThat(e).hasMessageThat().contains("syntax error at 'newline': expected expression"); + } +}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/config/FlagSetsFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/config/FlagSetsFunctionTest.java index a8c7352..7c46302 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/config/FlagSetsFunctionTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/config/FlagSetsFunctionTest.java
@@ -87,7 +87,7 @@ } @Test - public void flagSetsFunction_returns_origional_buildOptions() throws Exception { + public void flagSetsFunction_returns_original_buildOptions() throws Exception { // given original BuildOptions and an empty scl config name BuildOptions buildOptions = BuildOptions.getDefaultBuildOptionsForFragments(