2525import com .google .common .collect .ImmutableList ;
2626import com .google .common .collect .ImmutableMap ;
2727import com .google .devtools .build .docgen .annot .DocumentMethods ;
28+ import com .google .devtools .build .lib .bazel .bzlmod .ModuleFileGlobals .ModuleExtensionUsageBuilder .ModuleExtensionProxy ;
2829import com .google .devtools .build .lib .bazel .bzlmod .Version .ParseException ;
2930import com .google .devtools .build .lib .cmdline .RepositoryName ;
3031import java .util .ArrayList ;
@@ -63,7 +64,7 @@ public class ModuleFileGlobals {
6364 private final boolean ignoreDevDeps ;
6465 private final Module .Builder module ;
6566 private final Map <String , ModuleKey > deps = new LinkedHashMap <>();
66- private final List <ModuleExtensionProxy > extensionProxies = new ArrayList <>();
67+ private final List <ModuleExtensionUsageBuilder > extensionUsageBuilders = new ArrayList <>();
6768 private final Map <String , ModuleOverride > overrides = new HashMap <>();
6869 private final Map <String , RepoNameUsage > repoNameUsages = new HashMap <>();
6970
@@ -373,38 +374,37 @@ public void registerToolchains(Sequence<?> toolchainLabels) throws EvalException
373374 },
374375 useStarlarkThread = true )
375376 public ModuleExtensionProxy useExtension (
376- String extensionBzlFile , String extensionName , boolean devDependency , StarlarkThread thread )
377- throws EvalException {
378- ModuleExtensionProxy newProxy =
379- new ModuleExtensionProxy ( extensionBzlFile , extensionName , thread .getCallerLocation ());
377+ String extensionBzlFile , String extensionName , boolean devDependency , StarlarkThread thread ) {
378+ ModuleExtensionUsageBuilder newUsageBuilder =
379+ new ModuleExtensionUsageBuilder (
380+ extensionBzlFile , extensionName , thread .getCallerLocation ());
380381
381382 if (ignoreDevDeps && devDependency ) {
382383 // This is a no-op proxy.
383- return newProxy ;
384+ return newUsageBuilder . getProxy ( devDependency ) ;
384385 }
385386
386- // Find an existing proxy object corresponding to this extension.
387- for (ModuleExtensionProxy proxy : extensionProxies ) {
388- if (proxy .extensionBzlFile .equals (extensionBzlFile )
389- && proxy .extensionName .equals (extensionName )) {
390- return proxy ;
387+ // Find an existing usage builder corresponding to this extension.
388+ for (ModuleExtensionUsageBuilder usageBuilder : extensionUsageBuilders ) {
389+ if (usageBuilder .extensionBzlFile .equals (extensionBzlFile )
390+ && usageBuilder .extensionName .equals (extensionName )) {
391+ return usageBuilder . getProxy ( devDependency ) ;
391392 }
392393 }
393394
394395 // If no such proxy exists, we can just use a new one.
395- extensionProxies .add (newProxy );
396- return newProxy ;
396+ extensionUsageBuilders .add (newUsageBuilder );
397+ return newUsageBuilder . getProxy ( devDependency ) ;
397398 }
398399
399- @ StarlarkBuiltin (name = "module_extension_proxy" , documented = false )
400- class ModuleExtensionProxy implements Structure {
400+ class ModuleExtensionUsageBuilder {
401401 private final String extensionBzlFile ;
402402 private final String extensionName ;
403403 private final Location location ;
404404 private final HashBiMap <String , String > imports ;
405405 private final ImmutableList .Builder <Tag > tags ;
406406
407- ModuleExtensionProxy (String extensionBzlFile , String extensionName , Location location ) {
407+ ModuleExtensionUsageBuilder (String extensionBzlFile , String extensionName , Location location ) {
408408 this .extensionBzlFile = extensionBzlFile ;
409409 this .extensionName = extensionName ;
410410 this .location = location ;
@@ -422,50 +422,69 @@ ModuleExtensionUsage buildUsage() {
422422 .build ();
423423 }
424424
425- void addImport (String localRepoName , String exportedName , Location location )
426- throws EvalException {
427- RepositoryName .validateUserProvidedRepoName (localRepoName );
428- RepositoryName .validateUserProvidedRepoName (exportedName );
429- addRepoNameUsage (localRepoName , "by a use_repo() call" , location );
430- if (imports .containsValue (exportedName )) {
431- String collisionRepoName = imports .inverse ().get (exportedName );
432- throw Starlark .errorf (
433- "The repo exported as '%s' by module extension '%s' is already imported at %s" ,
434- exportedName , extensionName , repoNameUsages .get (collisionRepoName ).getWhere ());
435- }
436- imports .put (localRepoName , exportedName );
425+ /**
426+ * Creates a proxy with the specified dev_dependency bit that shares accumulated imports and
427+ * tags with all other such proxies, thus preserving their order across dev/non-dev deps.
428+ */
429+ ModuleExtensionProxy getProxy (boolean devDependency ) {
430+ return new ModuleExtensionProxy (devDependency );
437431 }
438432
439- @ Nullable
440- @ Override
441- public Object getValue (String tagName ) throws EvalException {
442- return new StarlarkValue () {
443- @ StarlarkMethod (
444- name = "call" ,
445- selfCall = true ,
446- documented = false ,
447- extraKeywords = @ Param (name = "kwargs" ),
448- useStarlarkThread = true )
449- public void call (Dict <String , Object > kwargs , StarlarkThread thread ) {
450- tags .add (
451- Tag .builder ()
452- .setTagName (tagName )
453- .setAttributeValues (kwargs )
454- .setLocation (thread .getCallerLocation ())
455- .build ());
433+ @ StarlarkBuiltin (name = "module_extension_proxy" , documented = false )
434+ class ModuleExtensionProxy implements Structure {
435+
436+ private final boolean devDependency ;
437+
438+ private ModuleExtensionProxy (boolean devDependency ) {
439+ this .devDependency = devDependency ;
440+ }
441+
442+ void addImport (String localRepoName , String exportedName , Location location )
443+ throws EvalException {
444+ RepositoryName .validateUserProvidedRepoName (localRepoName );
445+ RepositoryName .validateUserProvidedRepoName (exportedName );
446+ addRepoNameUsage (localRepoName , "by a use_repo() call" , location );
447+ if (imports .containsValue (exportedName )) {
448+ String collisionRepoName = imports .inverse ().get (exportedName );
449+ throw Starlark .errorf (
450+ "The repo exported as '%s' by module extension '%s' is already imported at %s" ,
451+ exportedName , extensionName , repoNameUsages .get (collisionRepoName ).getWhere ());
456452 }
457- } ;
458- }
453+ imports . put ( localRepoName , exportedName ) ;
454+ }
459455
460- @ Override
461- public ImmutableCollection <String > getFieldNames () {
462- return ImmutableList .of ();
463- }
456+ @ Nullable
457+ @ Override
458+ public Object getValue (String tagName ) throws EvalException {
459+ return new StarlarkValue () {
460+ @ StarlarkMethod (
461+ name = "call" ,
462+ selfCall = true ,
463+ documented = false ,
464+ extraKeywords = @ Param (name = "kwargs" ),
465+ useStarlarkThread = true )
466+ public void call (Dict <String , Object > kwargs , StarlarkThread thread ) {
467+ tags .add (
468+ Tag .builder ()
469+ .setTagName (tagName )
470+ .setAttributeValues (kwargs )
471+ .setDevDependency (devDependency )
472+ .setLocation (thread .getCallerLocation ())
473+ .build ());
474+ }
475+ };
476+ }
464477
465- @ Nullable
466- @ Override
467- public String getErrorMessageForUnknownField (String field ) {
468- return null ;
478+ @ Override
479+ public ImmutableCollection <String > getFieldNames () {
480+ return ImmutableList .of ();
481+ }
482+
483+ @ Nullable
484+ @ Override
485+ public String getErrorMessageForUnknownField (String field ) {
486+ return null ;
487+ }
469488 }
470489 }
471490
@@ -821,8 +840,8 @@ public Module buildModule() {
821840 .setDeps (ImmutableMap .copyOf (deps ))
822841 .setOriginalDeps (ImmutableMap .copyOf (deps ))
823842 .setExtensionUsages (
824- extensionProxies .stream ()
825- .map (ModuleExtensionProxy ::buildUsage )
843+ extensionUsageBuilders .stream ()
844+ .map (ModuleExtensionUsageBuilder ::buildUsage )
826845 .collect (toImmutableList ()))
827846 .build ();
828847 }
0 commit comments