Minor refactor of convenience symlink logic
- Eliminate ConfigGroup value object, instead push the Python transition into the SymlinkDefinition that needs it.
- Revert List of configs back to Set of configs (seems more natural and avoids changing or copying the collection in the caller).
- Tweak docstrings a little.
RELNOTES: None
PiperOrigin-RevId: 282594829
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java b/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java
index 271378e..9e2bd79 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java
@@ -13,7 +13,7 @@
// limitations under the License.
package com.google.devtools.build.lib.buildtool;
-import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.ImmutableSet.toImmutableSet;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
@@ -36,7 +36,6 @@
import java.util.List;
import java.util.Set;
import java.util.function.Function;
-import javax.annotation.Nullable;
/** Static utilities for managing output directory symlinks. */
public final class OutputDirectoryLinksUtils {
@@ -44,45 +43,28 @@
// Static utilities class.
private OutputDirectoryLinksUtils() {}
- /**
- * A grouping of a target configuration and its derived configurations, which, as a unit,
- * determine the candidate destinations for symlinks.
- */
- private static final class ConfigGroup {
-
- private static final PythonVersionTransition py2Transition =
- PythonVersionTransition.toConstant(PythonVersion.PY2);
-
- final BuildConfiguration targetConfig;
-
- @Nullable final BuildConfiguration py2Config;
-
- /**
- * Constructs from a given target configuration, using {@code configGetter} as a factory to make
- * configurations from options.
- */
- ConfigGroup(
- BuildConfiguration targetConfig, Function<BuildOptions, BuildConfiguration> configGetter) {
- this.targetConfig = targetConfig;
- this.py2Config = configGetter.apply(py2Transition.patch(targetConfig.getOptions()));
- }
- }
-
/** Represents a single kind of convenience symlink ({@code bazel-bin}, etc.). */
interface SymlinkDefinition {
/**
- * Returns the name for this symlink in the workspace. This is independent of the target
- * configuration(s).
+ * Returns the name for this symlink in the workspace.
+ *
+ * <p>Note that this is independent of the target configuration(s) that may help determine the
+ * symlink's destination.
*/
String getLinkName(String symlinkPrefix, String productName, String workspaceBaseName);
/**
- * Returns a list of candidate target paths for the symlink.
+ * Returns a list of candidate destination paths for the symlink.
*
* <p>The symlink should only be created if there is exactly one candidate.
+ *
+ * <p>{@code configGetter} is used to compute derived configurations, if needed. It is used for
+ * symlinks that link to the output directories of configs that are related to, but not included
+ * in, {@code targetConfigs}.
*/
- List<Path> getLinkPaths(
- List<ConfigGroup> configGroups,
+ Set<Path> getLinkPaths(
+ Set<BuildConfiguration> targetConfigs,
+ Function<BuildOptions, BuildConfiguration> configGetter,
RepositoryName repositoryName,
Path outputPath,
Path execRoot);
@@ -108,16 +90,16 @@
}
@Override
- public List<Path> getLinkPaths(
- List<ConfigGroup> configGroups,
+ public Set<Path> getLinkPaths(
+ Set<BuildConfiguration> targetConfigs,
+ Function<BuildOptions, BuildConfiguration> configGetter,
RepositoryName repositoryName,
Path outputPath,
Path execRoot) {
- return configGroups.stream()
- .map(group -> group.targetConfig)
+ return targetConfigs.stream()
.map(config -> configToRoot.apply(config, repositoryName).getRoot().asPath())
.distinct()
- .collect(toImmutableList());
+ .collect(toImmutableSet());
}
}
@@ -130,12 +112,13 @@
}
@Override
- public List<Path> getLinkPaths(
- List<ConfigGroup> configGroups,
+ public Set<Path> getLinkPaths(
+ Set<BuildConfiguration> targetConfigs,
+ Function<BuildOptions, BuildConfiguration> configGetter,
RepositoryName repositoryName,
Path outputPath,
Path execRoot) {
- return ImmutableList.of(execRoot);
+ return ImmutableSet.of(execRoot);
}
}
@@ -158,34 +141,39 @@
};
@Override
- public List<Path> getLinkPaths(
- List<ConfigGroup> configGroups,
+ public Set<Path> getLinkPaths(
+ Set<BuildConfiguration> targetConfigs,
+ Function<BuildOptions, BuildConfiguration> configGetter,
RepositoryName repositoryName,
Path outputPath,
Path execRoot) {
- return ImmutableList.of(outputPath);
+ return ImmutableSet.of(outputPath);
}
}
private enum Py2BinSymlink implements SymlinkDefinition {
INSTANCE;
+ private static final PythonVersionTransition py2Transition =
+ PythonVersionTransition.toConstant(PythonVersion.PY2);
+
@Override
public String getLinkName(String symlinkPrefix, String productName, String workspaceBaseName) {
return symlinkPrefix + "py2-bin";
}
@Override
- public List<Path> getLinkPaths(
- List<ConfigGroup> configGroups,
+ public Set<Path> getLinkPaths(
+ Set<BuildConfiguration> targetConfigs,
+ Function<BuildOptions, BuildConfiguration> configGetter,
RepositoryName repositoryName,
Path outputPath,
Path execRoot) {
- return configGroups.stream()
- .map(group -> group.py2Config)
+ return targetConfigs.stream()
+ .map(config -> configGetter.apply(py2Transition.patch(config.getOptions())))
.map(config -> config.getBinDirectory(repositoryName).getRoot().asPath())
.distinct()
- .collect(toImmutableList());
+ .collect(toImmutableSet());
}
}
@@ -263,11 +251,6 @@
String workspaceBaseName = workspace.getBaseName();
RepositoryName repositoryName = RepositoryName.createFromValidStrippedName(workspaceName);
- List<ConfigGroup> configGroups =
- targetConfigs.stream()
- .map(targetConfig -> new ConfigGroup(targetConfig, configGetter))
- .collect(toImmutableList());
-
List<SymlinkDefinition> defs =
getLinkDefinitions(
/*includeGenfiles=*/ createGenfilesSymlink, /*includePy2Bin=*/ createPy2BinSymlink);
@@ -277,8 +260,9 @@
// already created a link by this name
continue;
}
- List<Path> candidatePaths =
- definition.getLinkPaths(configGroups, repositoryName, outputPath, execRoot);
+ Set<Path> candidatePaths =
+ definition.getLinkPaths(
+ targetConfigs, configGetter, repositoryName, outputPath, execRoot);
if (candidatePaths.size() == 1) {
createLink(workspace, symlinkName, Iterables.getOnlyElement(candidatePaths), failures);
} else {