Skip to content

Commit

Permalink
bzlmod: Add dev_dependency support
Browse files Browse the repository at this point in the history
- `bazel_dep` and `use_extension` with `dev_dependency=True` will be ignored in MODULE.bazel file of non-root modules.
- Add an option `--ignore_dev_dependency` to ignore those dependencies in root module's MODULE.bazel file. This will be useful to test if your current MODULE.bazel still works when your project is used as a dependency.

(#13316)

PiperOrigin-RevId: 400720591
  • Loading branch information
meteorcloudy authored and copybara-github committed Oct 4, 2021
1 parent 630be02 commit e83858b
Show file tree
Hide file tree
Showing 11 changed files with 275 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ public class BazelRepositoryModule extends BlazeModule {
// on WorkspaceFileValue is not registered for each FileStateValue.
private final ManagedDirectoriesKnowledgeImpl managedDirectoriesKnowledge;
private final AtomicBoolean enableBzlmod = new AtomicBoolean(false);
private final AtomicBoolean ignoreDevDeps = new AtomicBoolean(false);
private SingleExtensionEvalFunction singleExtensionEvalFunction;

public BazelRepositoryModule() {
Expand Down Expand Up @@ -372,6 +373,7 @@ public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
}

enableBzlmod.set(repoOptions.enableBzlmod);
ignoreDevDeps.set(repoOptions.ignoreDevDependency);

if (repoOptions.registries != null && !repoOptions.registries.isEmpty()) {
registries = repoOptions.registries;
Expand Down Expand Up @@ -441,7 +443,8 @@ public ImmutableList<Injected> getPrecomputedValues() {
RepositoryDelegatorFunction.DEPENDENCY_FOR_UNCONDITIONAL_CONFIGURING,
RepositoryDelegatorFunction.DONT_FETCH_UNCONDITIONALLY),
PrecomputedValue.injected(RepositoryDelegatorFunction.ENABLE_BZLMOD, enableBzlmod.get()),
PrecomputedValue.injected(ModuleFileFunction.REGISTRIES, registries));
PrecomputedValue.injected(ModuleFileFunction.REGISTRIES, registries),
PrecomputedValue.injected(ModuleFileFunction.IGNORE_DEV_DEPS, ignoreDevDeps.get()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
public class ModuleFileFunction implements SkyFunction {

public static final Precomputed<List<String>> REGISTRIES = new Precomputed<>("registries");
public static final Precomputed<Boolean> IGNORE_DEV_DEPS =
new Precomputed<>("ignore_dev_dependency");

private final RegistryFactory registryFactory;
private final Path workspaceRoot;
Expand Down Expand Up @@ -97,6 +99,8 @@ public SkyValue compute(SkyKey skyKey, Environment env)
getModuleFileResult.moduleFileContents,
getModuleFileResult.registry,
moduleKey,
// Dev dependencies should always be ignored if the current module isn't the root module
/* ignoreDevDeps= */ true,
starlarkSemantics,
env);

Expand Down Expand Up @@ -133,7 +137,13 @@ private SkyValue computeForRootModule(StarlarkSemantics starlarkSemantics, Envir
}
byte[] moduleFile = readFile(moduleFilePath.asPath());
ModuleFileGlobals moduleFileGlobals =
execModuleFile(moduleFile, /*registry=*/ null, ModuleKey.ROOT, starlarkSemantics, env);
execModuleFile(
moduleFile,
/*registry=*/ null,
ModuleKey.ROOT,
/* ignoreDevDeps= */ Objects.requireNonNull(IGNORE_DEV_DEPS.get(env)),
starlarkSemantics,
env);
Module module = moduleFileGlobals.buildModule();

// Check that overrides don't contain the root module itself.
Expand All @@ -158,6 +168,7 @@ private ModuleFileGlobals execModuleFile(
byte[] moduleFile,
@Nullable Registry registry,
ModuleKey moduleKey,
boolean ignoreDevDeps,
StarlarkSemantics starlarkSemantics,
Environment env)
throws ModuleFileFunctionException, InterruptedException {
Expand All @@ -168,7 +179,7 @@ private ModuleFileGlobals execModuleFile(
throw errorf(Code.BAD_MODULE, "error parsing MODULE.bazel file for %s", moduleKey);
}

ModuleFileGlobals moduleFileGlobals = new ModuleFileGlobals(moduleKey, registry);
ModuleFileGlobals moduleFileGlobals = new ModuleFileGlobals(moduleKey, registry, ignoreDevDeps);
try (Mutability mu = Mutability.create("module file", moduleKey)) {
net.starlark.java.eval.Module predeclaredEnv =
getPredeclaredEnv(moduleFileGlobals, starlarkSemantics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,16 @@
@DocumentMethods
public class ModuleFileGlobals {
private boolean moduleCalled = false;
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 Map<String, ModuleOverride> overrides = new HashMap<>();
private final Map<String, RepoNameUsage> repoNameUsages = new HashMap<>();

public ModuleFileGlobals(ModuleKey key, @Nullable Registry registry) {
public ModuleFileGlobals(ModuleKey key, @Nullable Registry registry, boolean ignoreDevDeps) {
module = Module.builder().setKey(key).setRegistry(registry);
this.ignoreDevDeps = ignoreDevDeps;
}

@AutoValue
Expand Down Expand Up @@ -168,9 +170,18 @@ public void module(
named = true,
positional = false,
defaultValue = "''"),
@Param(
name = "dev_dependency",
doc =
"If true, this dependency will be ignored if the current module is not the root"
+ " module or `--ignore_dev_dependency` is enabled.",
named = true,
positional = false,
defaultValue = "False"),
},
useStarlarkThread = true)
public void bazelDep(String name, String version, String repoName, StarlarkThread thread)
public void bazelDep(
String name, String version, String repoName, boolean devDependency, StarlarkThread thread)
throws EvalException {
if (repoName.isEmpty()) {
repoName = name;
Expand All @@ -182,7 +193,11 @@ public void bazelDep(String name, String version, String repoName, StarlarkThrea
} catch (ParseException e) {
throw new EvalException("Invalid version in bazel_dep()", e);
}
deps.put(repoName, ModuleKey.create(name, parsedVersion));

if (!(ignoreDevDeps && devDependency)) {
deps.put(repoName, ModuleKey.create(name, parsedVersion));
}

addRepoNameUsage(repoName, "by a bazel_dep", thread.getCallerLocation());
}

Expand All @@ -200,10 +215,19 @@ public void bazelDep(String name, String version, String repoName, StarlarkThrea
doc =
"The name of the module extension to use. A symbol with this name must be exported"
+ " by the Starlark file."),
@Param(
name = "dev_dependency",
doc =
"If true, this usage of the module extension will be ignored if the current module"
+ " is not the root module or `--ignore_dev_dependency` is enabled.",
named = true,
positional = false,
defaultValue = "False"),
},
useStarlarkThread = true)
public ModuleExtensionProxy useExtension(
String extensionBzlFile, String extensionName, StarlarkThread thread) throws EvalException {
String extensionBzlFile, String extensionName, boolean devDependency, StarlarkThread thread)
throws EvalException {
for (ModuleExtensionProxy proxy : extensionProxies) {
if (proxy.extensionBzlFile.equals(extensionBzlFile)
&& proxy.extensionName.equals(extensionName)) {
Expand All @@ -212,7 +236,11 @@ public ModuleExtensionProxy useExtension(
}
ModuleExtensionProxy proxy =
new ModuleExtensionProxy(extensionBzlFile, extensionName, thread.getCallerLocation());
extensionProxies.add(proxy);

if (!(ignoreDevDeps && devDependency)) {
extensionProxies.add(proxy);
}

return proxy;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,18 @@ public class RepositoryOptions extends OptionsBase {
+ "looking into the WORKSPACE file.")
public boolean enableBzlmod;

@Option(
name = "ignore_dev_dependency",
defaultValue = "false",
documentationCategory = OptionDocumentationCategory.BAZEL_CLIENT_OPTIONS,
effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS},
help =
"If true, Bazel ignores `bazel_dep` and `use_extension` declared as `dev_dependency` in "
+ "the MODULE.bazel of the root module. Note that, those dev dependencies are always "
+ "ignored in the MODULE.bazel if it's not the root module regardless of the value "
+ "of this flag.")
public boolean ignoreDevDependency;

/**
* Converts from an equals-separated pair of strings into RepositoryName->PathFragment mapping.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public void setup() throws Exception {
driver = new SequentialBuildDriver(evaluator);

PrecomputedValue.STARLARK_SEMANTICS.set(differencer, StarlarkSemantics.DEFAULT);
ModuleFileFunction.IGNORE_DEV_DEPS.set(differencer, false);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ public void setup() throws Exception {
differencer, ImmutableSet.of());
RepositoryDelegatorFunction.RESOLVED_FILE_FOR_VERIFICATION.set(differencer, Optional.empty());
RepositoryDelegatorFunction.ENABLE_BZLMOD.set(differencer, true);
ModuleFileFunction.IGNORE_DEV_DEPS.set(differencer, false);
}

@Test
Expand Down Expand Up @@ -264,6 +265,99 @@ public void testSimpleDiamond() throws Exception {
.build());
}

@Test
public void testDevDependency() throws Exception {
scratch.file(
workspaceRoot.getRelative("MODULE.bazel").getPathString(),
"module(name='A',version='0.1')",
"bazel_dep(name='B',version='1.0')",
"bazel_dep(name='C',version='1.0',dev_dependency=True)");
FakeRegistry registry =
registryFactory
.newFakeRegistry("/foo")
.addModule(
createModuleKey("B", "1.0"),
"module(name='B', version='1.0')",
"bazel_dep(name='C',version='2.0',dev_dependency=True)")
.addModule(createModuleKey("C", "1.0"), "module(name='C', version='1.0')")
.addModule(createModuleKey("C", "2.0"), "module(name='C', version='2.0')");
ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));

EvaluationResult<DiscoveryValue> result =
driver.evaluate(ImmutableList.of(DiscoveryValue.KEY), evaluationContext);
if (result.hasError()) {
fail(result.getError().toString());
}
DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY);
assertThat(discoveryValue.getDepGraph())
.containsExactly(
ModuleKey.ROOT,
Module.builder()
.setName("A")
.setVersion(Version.parse("0.1"))
.setKey(ModuleKey.ROOT)
.addDep("B", createModuleKey("B", "1.0"))
.addDep("C", createModuleKey("C", "1.0"))
.build(),
createModuleKey("B", "1.0"),
Module.builder()
.setName("B")
.setVersion(Version.parse("1.0"))
.setKey(createModuleKey("B", "1.0"))
.setRegistry(registry)
.build(),
createModuleKey("C", "1.0"),
Module.builder()
.setName("C")
.setVersion(Version.parse("1.0"))
.setKey(createModuleKey("C", "1.0"))
.setRegistry(registry)
.build());
}

@Test
public void testIgnoreDevDependency() throws Exception {
scratch.file(
workspaceRoot.getRelative("MODULE.bazel").getPathString(),
"module(name='A',version='0.1')",
"bazel_dep(name='B',version='1.0')",
"bazel_dep(name='C',version='1.0',dev_dependency=True)");
FakeRegistry registry =
registryFactory
.newFakeRegistry("/foo")
.addModule(
createModuleKey("B", "1.0"),
"module(name='B', version='1.0')",
"bazel_dep(name='C',version='2.0',dev_dependency=True)")
.addModule(createModuleKey("C", "1.0"), "module(name='C', version='1.0')")
.addModule(createModuleKey("C", "2.0"), "module(name='C', version='2.0')");
ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
ModuleFileFunction.IGNORE_DEV_DEPS.set(differencer, true);

EvaluationResult<DiscoveryValue> result =
driver.evaluate(ImmutableList.of(DiscoveryValue.KEY), evaluationContext);
if (result.hasError()) {
fail(result.getError().toString());
}
DiscoveryValue discoveryValue = result.get(DiscoveryValue.KEY);
assertThat(discoveryValue.getDepGraph())
.containsExactly(
ModuleKey.ROOT,
Module.builder()
.setName("A")
.setVersion(Version.parse("0.1"))
.setKey(ModuleKey.ROOT)
.addDep("B", createModuleKey("B", "1.0"))
.build(),
createModuleKey("B", "1.0"),
Module.builder()
.setName("B")
.setVersion(Version.parse("1.0"))
.setKey(createModuleKey("B", "1.0"))
.setRegistry(registry)
.build());
}

@Test
public void testCircularDependency() throws Exception {
scratch.file(
Expand Down
Loading

0 comments on commit e83858b

Please sign in to comment.