14
14
15
15
package com .google .devtools .build .lib .bazel .bzlmod ;
16
16
17
- import static com .google .common .collect .ImmutableList .toImmutableList ;
18
17
import static com .google .common .collect .ImmutableSet .toImmutableSet ;
19
18
20
19
import com .google .auto .value .AutoValue ;
21
20
import com .google .common .base .Preconditions ;
21
+ import com .google .common .collect .ImmutableListMultimap ;
22
22
import com .google .common .collect .ImmutableSet ;
23
23
import com .google .common .collect .ImmutableSortedSet ;
24
- import com .google .common .collect .Iterables ;
25
24
import com .google .common .collect .Sets ;
26
25
import com .google .devtools .build .docgen .annot .DocCategory ;
26
+ import com .google .devtools .build .lib .bazel .bzlmod .ModuleExtensionUsage .Proxy ;
27
27
import com .google .devtools .build .lib .cmdline .RepositoryName ;
28
28
import com .google .devtools .build .lib .events .Event ;
29
29
import com .google .devtools .build .lib .events .EventHandler ;
30
+ import com .google .devtools .build .lib .vfs .PathFragment ;
30
31
import com .ryanharter .auto .value .gson .GenerateTypeAdapter ;
31
32
import java .util .ArrayList ;
32
33
import java .util .Collection ;
33
34
import java .util .LinkedHashSet ;
34
35
import java .util .Optional ;
35
36
import java .util .Set ;
36
- import java .util .stream .Stream ;
37
37
import javax .annotation .Nullable ;
38
38
import net .starlark .java .annot .StarlarkBuiltin ;
39
39
import net .starlark .java .eval .EvalException ;
@@ -171,20 +171,8 @@ static ModuleExtensionMetadata create(
171
171
}
172
172
173
173
public Optional <RootModuleFileFixup > generateFixup (
174
- Collection < ModuleExtensionUsage > usages , Set <String > allRepos , EventHandler eventHandler )
174
+ ModuleExtensionUsage rootUsage , Set <String > allRepos , EventHandler eventHandler )
175
175
throws EvalException {
176
- var rootUsages =
177
- usages .stream ()
178
- .filter (usage -> usage .getUsingModule ().equals (ModuleKey .ROOT ))
179
- .collect (toImmutableList ());
180
- if (rootUsages .isEmpty ()) {
181
- // The root module doesn't use the current extension. Do not suggest fixes as the user isn't
182
- // expected to modify any other module's MODULE.bazel file.
183
- return Optional .empty ();
184
- }
185
- // Every module only has at most a single usage of a given extension.
186
- ModuleExtensionUsage rootUsage = Iterables .getOnlyElement (rootUsages );
187
-
188
176
var rootModuleDirectDevDeps = getRootModuleDirectDevDeps (allRepos );
189
177
var rootModuleDirectDeps = getRootModuleDirectDeps (allRepos );
190
178
if (rootModuleDirectDevDeps .isEmpty () && rootModuleDirectDeps .isEmpty ()) {
@@ -311,73 +299,52 @@ private static Optional<RootModuleFileFixup> generateFixup(
311
299
312
300
message += "Fix the use_repo calls by running 'bazel mod tidy'." ;
313
301
314
- var buildozerCommands =
315
- Stream .of (
316
- makeUseRepoCommand (
317
- "use_repo_add" ,
318
- false ,
319
- importsToAdd ,
320
- extensionBzlFile ,
321
- extensionName ,
322
- rootUsage .getIsolationKey ()),
323
- makeUseRepoCommand (
324
- "use_repo_remove" ,
325
- false ,
326
- importsToRemove ,
327
- extensionBzlFile ,
328
- extensionName ,
329
- rootUsage .getIsolationKey ()),
330
- makeUseRepoCommand (
331
- "use_repo_add" ,
332
- true ,
333
- devImportsToAdd ,
334
- extensionBzlFile ,
335
- extensionName ,
336
- rootUsage .getIsolationKey ()),
337
- makeUseRepoCommand (
338
- "use_repo_remove" ,
339
- true ,
340
- devImportsToRemove ,
341
- extensionBzlFile ,
342
- extensionName ,
343
- rootUsage .getIsolationKey ()))
344
- .flatMap (Optional ::stream )
345
- .collect (toImmutableList ());
302
+ var moduleFilePathToCommandsBuilder = ImmutableListMultimap .<PathFragment , String >builder ();
303
+ // Repos to add are easy: always add them to the first proxy of the correct type.
304
+ if (!importsToAdd .isEmpty ()) {
305
+ Proxy firstNonDevProxy =
306
+ rootUsage .getProxies ().stream ().filter (p -> !p .isDevDependency ()).findFirst ().get ();
307
+ moduleFilePathToCommandsBuilder .put (
308
+ firstNonDevProxy .getContainingModuleFilePath (),
309
+ makeUseRepoCommand ("use_repo_add" , firstNonDevProxy .getProxyName (), importsToAdd ));
310
+ }
311
+ if (!devImportsToAdd .isEmpty ()) {
312
+ Proxy firstDevProxy =
313
+ rootUsage .getProxies ().stream ().filter (p -> p .isDevDependency ()).findFirst ().get ();
314
+ moduleFilePathToCommandsBuilder .put (
315
+ firstDevProxy .getContainingModuleFilePath (),
316
+ makeUseRepoCommand ("use_repo_add" , firstDevProxy .getProxyName (), devImportsToAdd ));
317
+ }
318
+ // Repos to remove are a bit trickier: remove them from the proxy that actually imported them.
319
+ for (Proxy proxy : rootUsage .getProxies ()) {
320
+ var toRemove =
321
+ ImmutableSortedSet .copyOf (
322
+ Sets .intersection (
323
+ proxy .getImports ().values (),
324
+ proxy .isDevDependency () ? devImportsToRemove : importsToRemove ));
325
+ if (!toRemove .isEmpty ()) {
326
+ moduleFilePathToCommandsBuilder .put (
327
+ proxy .getContainingModuleFilePath (),
328
+ makeUseRepoCommand ("use_repo_remove" , proxy .getProxyName (), toRemove ));
329
+ }
330
+ }
346
331
347
332
eventHandler .handle (Event .warn (rootUsage .getProxies ().getFirst ().getLocation (), message ));
348
- return Optional .of (new RootModuleFileFixup (buildozerCommands , rootUsage ));
333
+ return Optional .of (new RootModuleFileFixup (moduleFilePathToCommandsBuilder . build () , rootUsage ));
349
334
}
350
335
351
- private static Optional <String > makeUseRepoCommand (
352
- String cmd ,
353
- boolean devDependency ,
354
- Collection <String > repos ,
355
- String extensionBzlFile ,
356
- String extensionName ,
357
- Optional <ModuleExtensionId .IsolationKey > isolationKey ) {
358
- if (repos .isEmpty ()) {
359
- return Optional .empty ();
360
- }
361
-
336
+ private static String makeUseRepoCommand (String cmd , String proxyName , Collection <String > repos ) {
362
337
var commandParts = new ArrayList <String >();
363
338
commandParts .add (cmd );
364
- if (isolationKey .isPresent ()) {
365
- commandParts .add (isolationKey .get ().getUsageExportedName ());
366
- } else {
367
- if (devDependency ) {
368
- commandParts .add ("dev" );
369
- }
370
- commandParts .add (extensionBzlFile );
371
- commandParts .add (extensionName );
372
- }
339
+ commandParts .add (proxyName .isEmpty () ? "_unnamed_usage" : proxyName );
373
340
commandParts .addAll (repos );
374
- return Optional . of ( String .join (" " , commandParts ) );
341
+ return String .join (" " , commandParts );
375
342
}
376
343
377
344
private Optional <ImmutableSet <String >> getRootModuleDirectDeps (Set <String > allRepos )
378
345
throws EvalException {
379
- switch (getUseAllRepos ()) {
380
- case NO :
346
+ return switch (getUseAllRepos ()) {
347
+ case NO -> {
381
348
if (getExplicitRootModuleDirectDeps () != null ) {
382
349
Set <String > invalidRepos = Sets .difference (getExplicitRootModuleDirectDeps (), allRepos );
383
350
if (!invalidRepos .isEmpty ()) {
@@ -387,13 +354,11 @@ private Optional<ImmutableSet<String>> getRootModuleDirectDeps(Set<String> allRe
387
354
String .join (", " , invalidRepos ));
388
355
}
389
356
}
390
- return Optional .ofNullable (getExplicitRootModuleDirectDeps ());
391
- case REGULAR :
392
- return Optional .of (ImmutableSet .copyOf (allRepos ));
393
- case DEV :
394
- return Optional .of (ImmutableSet .of ());
395
- }
396
- throw new IllegalStateException ("not reached" );
357
+ yield Optional .ofNullable (getExplicitRootModuleDirectDeps ());
358
+ }
359
+ case REGULAR -> Optional .of (ImmutableSet .copyOf (allRepos ));
360
+ case DEV -> Optional .of (ImmutableSet .of ());
361
+ };
397
362
}
398
363
399
364
private Optional <ImmutableSet <String >> getRootModuleDirectDevDeps (Set <String > allRepos )
0 commit comments