Skip to content

Commit

Permalink
Use a dedicated proxy builder class
Browse files Browse the repository at this point in the history
  • Loading branch information
fmeum committed Mar 29, 2023
1 parent a18f6cc commit 9a3bdc8
Showing 1 changed file with 75 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.docgen.annot.DocumentMethods;
import com.google.devtools.build.lib.bazel.bzlmod.ModuleFileGlobals.ModuleExtensionProxyBuilder.ModuleExtensionProxy;
import com.google.devtools.build.lib.bazel.bzlmod.Version.ParseException;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import java.util.ArrayList;
Expand Down Expand Up @@ -63,7 +64,7 @@ public class ModuleFileGlobals {
private final boolean ignoreDevDeps;
private final Module.Builder module;
private final Map<String, ModuleKey> deps = new LinkedHashMap<>();
private final List<ModuleExtensionProxy> extensionProxies = new ArrayList<>();
private final List<ModuleExtensionProxyBuilder> extensionProxyBuilders = new ArrayList<>();
private final Map<String, ModuleOverride> overrides = new HashMap<>();
private final Map<String, RepoNameUsage> repoNameUsages = new HashMap<>();

Expand Down Expand Up @@ -376,60 +377,41 @@ public void registerToolchains(Sequence<?> toolchainLabels) throws EvalException
useStarlarkThread = true)
public ModuleExtensionProxy useExtension(
String extensionBzlFile, String extensionName, boolean devDependency, StarlarkThread thread) {
ModuleExtensionProxy newProxy =
new ModuleExtensionProxy(extensionBzlFile, extensionName, thread.getCallerLocation());
ModuleExtensionProxyBuilder newProxyBuilder = new ModuleExtensionProxyBuilder(extensionBzlFile,
extensionName, thread.getCallerLocation());

if (ignoreDevDeps && devDependency) {
// This is a no-op proxy.
return newProxy.withDevDependency(devDependency);
return newProxyBuilder.getProxy(devDependency);
}

// Find an existing proxy object corresponding to this extension.
for (ModuleExtensionProxy proxy : extensionProxies) {
if (proxy.extensionBzlFile.equals(extensionBzlFile)
&& proxy.extensionName.equals(extensionName)) {
return proxy.withDevDependency(devDependency);
// Find an existing proxy builder corresponding to this extension.
for (ModuleExtensionProxyBuilder proxyBuilder : extensionProxyBuilders) {
if (proxyBuilder.extensionBzlFile.equals(extensionBzlFile)
&& proxyBuilder.extensionName.equals(extensionName)) {
// All proxies returned by withDevDependency share a common set of imports and tags.
return proxyBuilder.getProxy(devDependency);
}
}

// If no such proxy exists, we can just use a new one.
extensionProxies.add(newProxy);
return newProxy.withDevDependency(devDependency);
extensionProxyBuilders.add(newProxyBuilder);
return newProxyBuilder.getProxy(devDependency);
}

@StarlarkBuiltin(name = "module_extension_proxy", documented = false)
class ModuleExtensionProxy implements Structure {
class ModuleExtensionProxyBuilder {
private final String extensionBzlFile;
private final String extensionName;
private final Location location;
private final HashBiMap<String, String> imports;
private final ImmutableList.Builder<Tag> tags;
private final boolean devDependency;

ModuleExtensionProxy(String extensionBzlFile, String extensionName, Location location) {
ModuleExtensionProxyBuilder(String extensionBzlFile, String extensionName, Location location) {
this.extensionBzlFile = extensionBzlFile;
this.extensionName = extensionName;
this.location = location;
this.imports = HashBiMap.create();
this.tags = ImmutableList.builder();
this.devDependency = false;
}

private ModuleExtensionProxy(ModuleExtensionProxy other, boolean devDependency) {
this.extensionBzlFile = other.extensionBzlFile;
this.extensionName = other.extensionName;
this.location = other.location;
this.imports = other.imports;
this.tags = other.tags;
this.devDependency = devDependency;
}

/**
* Creates a proxy with the specified devDependency bit that shares accumulated imports and tags
* with the current one, thus preserving tag specification order.
*/
ModuleExtensionProxy withDevDependency(boolean devDependency) {
return devDependency ? new ModuleExtensionProxy(this, true) : this;
}

ModuleExtensionUsage buildUsage() {
Expand All @@ -442,51 +424,69 @@ ModuleExtensionUsage buildUsage() {
.build();
}

void addImport(String localRepoName, String exportedName, Location location)
throws EvalException {
RepositoryName.validateUserProvidedRepoName(localRepoName);
RepositoryName.validateUserProvidedRepoName(exportedName);
addRepoNameUsage(localRepoName, "by a use_repo() call", location);
if (imports.containsValue(exportedName)) {
String collisionRepoName = imports.inverse().get(exportedName);
throw Starlark.errorf(
"The repo exported as '%s' by module extension '%s' is already imported at %s",
exportedName, extensionName, repoNameUsages.get(collisionRepoName).getWhere());
}
imports.put(localRepoName, exportedName);
/**
* Creates a proxy with the specified dev_dependency bit that shares accumulated imports and
* tags with all other such proxies, thus preserving their order across dev/non-dev deps.
*/
ModuleExtensionProxy getProxy(boolean devDependency) {
return new ModuleExtensionProxy(devDependency);
}

@Nullable
@Override
public Object getValue(String tagName) throws EvalException {
return new StarlarkValue() {
@StarlarkMethod(
name = "call",
selfCall = true,
documented = false,
extraKeywords = @Param(name = "kwargs"),
useStarlarkThread = true)
public void call(Dict<String, Object> kwargs, StarlarkThread thread) {
tags.add(
Tag.builder()
.setTagName(tagName)
.setAttributeValues(kwargs)
.setDevDependency(devDependency)
.setLocation(thread.getCallerLocation())
.build());
@StarlarkBuiltin(name = "module_extension_proxy", documented = false)
class ModuleExtensionProxy implements Structure {

private final boolean devDependency;

private ModuleExtensionProxy(boolean devDependency) {
this.devDependency = devDependency;
}

void addImport(String localRepoName, String exportedName, Location location)
throws EvalException {
RepositoryName.validateUserProvidedRepoName(localRepoName);
RepositoryName.validateUserProvidedRepoName(exportedName);
addRepoNameUsage(localRepoName, "by a use_repo() call", location);
if (imports.containsValue(exportedName)) {
String collisionRepoName = imports.inverse().get(exportedName);
throw Starlark.errorf(
"The repo exported as '%s' by module extension '%s' is already imported at %s",
exportedName, extensionName, repoNameUsages.get(collisionRepoName).getWhere());
}
};
}
imports.put(localRepoName, exportedName);
}

@Override
public ImmutableCollection<String> getFieldNames() {
return ImmutableList.of();
}
@Nullable
@Override
public Object getValue(String tagName) throws EvalException {
return new StarlarkValue() {
@StarlarkMethod(
name = "call",
selfCall = true,
documented = false,
extraKeywords = @Param(name = "kwargs"),
useStarlarkThread = true)
public void call(Dict<String, Object> kwargs, StarlarkThread thread) {
tags.add(
Tag.builder()
.setTagName(tagName)
.setAttributeValues(kwargs)
.setDevDependency(devDependency)
.setLocation(thread.getCallerLocation())
.build());
}
};
}

@Nullable
@Override
public String getErrorMessageForUnknownField(String field) {
return null;
@Override
public ImmutableCollection<String> getFieldNames() {
return ImmutableList.of();
}

@Nullable
@Override
public String getErrorMessageForUnknownField(String field) {
return null;
}
}
}

Expand Down Expand Up @@ -843,8 +843,8 @@ public Module buildModule() {
.setDeps(ImmutableMap.copyOf(deps))
.setOriginalDeps(ImmutableMap.copyOf(deps))
.setExtensionUsages(
extensionProxies.stream()
.map(ModuleExtensionProxy::buildUsage)
extensionProxyBuilders.stream()
.map(ModuleExtensionProxyBuilder::buildUsage)
.collect(toImmutableList()))
.build();
}
Expand Down

0 comments on commit 9a3bdc8

Please sign in to comment.