@@ -13,6 +13,7 @@ import (
13
13
"io/ioutil"
14
14
"log"
15
15
"sort"
16
+ "sync"
16
17
"text/tabwriter"
17
18
18
19
"github.com/golang/dep"
@@ -362,82 +363,121 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana
362
363
363
364
logger .Println ("Checking upstream projects:" )
364
365
366
+ // BasicStatus channel to collect all the BasicStatus
367
+ bsCh := make (chan * BasicStatus , len (slp ))
368
+
369
+ // Error channel to collect all the errors
370
+ errorCh := make (chan error , len (slp ))
371
+
372
+ var wg sync.WaitGroup
373
+
365
374
for i , proj := range slp {
375
+ wg .Add (1 )
366
376
logger .Printf ("(%d/%d) %s\n " , i + 1 , len (slp ), proj .Ident ().ProjectRoot )
367
377
368
- bs := BasicStatus {
369
- ProjectRoot : string (proj .Ident ().ProjectRoot ),
370
- PackageCount : len (proj .Packages ()),
371
- }
378
+ go func (proj gps.LockedProject ) {
379
+ defer wg .Done ()
372
380
373
- // Get children only for specific outputers
374
- // in order to avoid slower status process
375
- switch out .(type ) {
376
- case * dotOutput :
377
- ptr , err := sm .ListPackages (proj .Ident (), proj .Version ())
378
-
379
- if err != nil {
380
- return digestMismatch , hasMissingPkgs , errors .Wrapf (err , "analysis of %s package failed" , proj .Ident ().ProjectRoot )
381
+ bs := BasicStatus {
382
+ ProjectRoot : string (proj .Ident ().ProjectRoot ),
383
+ PackageCount : len (proj .Packages ()),
381
384
}
382
385
383
- prm , _ := ptr .ToReachMap (true , false , false , nil )
384
- bs .Children = prm .FlattenFn (paths .IsStandardImportPath )
385
- }
386
+ // Get children only for specific outputers
387
+ // in order to avoid slower status process
388
+ switch out .(type ) {
389
+ case * dotOutput :
390
+ ptr , err := sm .ListPackages (proj .Ident (), proj .Version ())
386
391
387
- // Split apart the version from the lock into its constituent parts
388
- switch tv := proj .Version ().(type ) {
389
- case gps.UnpairedVersion :
390
- bs .Version = tv
391
- case gps.Revision :
392
- bs .Revision = tv
393
- case gps.PairedVersion :
394
- bs .Version = tv .Unpair ()
395
- bs .Revision = tv .Revision ()
396
- }
392
+ if err != nil {
393
+ errorCh <- err
394
+ }
397
395
398
- // Check if the manifest has an override for this project. If so,
399
- // set that as the constraint.
400
- if pp , has := p .Manifest .Ovr [proj .Ident ().ProjectRoot ]; has && pp .Constraint != nil {
401
- bs .hasOverride = true
402
- bs .Constraint = pp .Constraint
403
- } else {
404
- bs .Constraint = gps .Any ()
405
- for _ , c := range cm [bs .ProjectRoot ] {
406
- bs .Constraint = c .Intersect (bs .Constraint )
396
+ prm , _ := ptr .ToReachMap (true , false , false , nil )
397
+ bs .Children = prm .FlattenFn (paths .IsStandardImportPath )
398
+ }
399
+
400
+ // Split apart the version from the lock into its constituent parts
401
+ switch tv := proj .Version ().(type ) {
402
+ case gps.UnpairedVersion :
403
+ bs .Version = tv
404
+ case gps.Revision :
405
+ bs .Revision = tv
406
+ case gps.PairedVersion :
407
+ bs .Version = tv .Unpair ()
408
+ bs .Revision = tv .Revision ()
407
409
}
408
- }
409
410
410
- // Only if we have a non-rev and non-plain version do/can we display
411
- // anything wrt the version's updateability.
412
- if bs .Version != nil && bs .Version .Type () != gps .IsVersion {
413
- c , has := p .Manifest .Constraints [proj .Ident ().ProjectRoot ]
414
- if ! has {
415
- c .Constraint = gps .Any ()
411
+ // Check if the manifest has an override for this project. If so,
412
+ // set that as the constraint.
413
+ if pp , has := p .Manifest .Ovr [proj .Ident ().ProjectRoot ]; has && pp .Constraint != nil {
414
+ bs .hasOverride = true
415
+ bs .Constraint = pp .Constraint
416
+ } else {
417
+ bs .Constraint = gps .Any ()
418
+ for _ , c := range cm [bs .ProjectRoot ] {
419
+ bs .Constraint = c .Intersect (bs .Constraint )
420
+ }
416
421
}
417
- // TODO: This constraint is only the constraint imposed by the
418
- // current project, not by any transitive deps. As a result,
419
- // transitive project deps will always show "any" here.
420
- bs .Constraint = c .Constraint
421
-
422
- vl , err := sm .ListVersions (proj .Ident ())
423
- if err == nil {
424
- gps .SortPairedForUpgrade (vl )
425
-
426
- for _ , v := range vl {
427
- // Because we've sorted the version list for
428
- // upgrade, the first version we encounter that
429
- // matches our constraint will be what we want.
430
- if c .Constraint .Matches (v ) {
431
- bs .Latest = v .Revision ()
432
- break
422
+
423
+ // Only if we have a non-rev and non-plain version do/can we display
424
+ // anything wrt the version's updateability.
425
+ if bs .Version != nil && bs .Version .Type () != gps .IsVersion {
426
+ c , has := p .Manifest .Constraints [proj .Ident ().ProjectRoot ]
427
+ if ! has {
428
+ c .Constraint = gps .Any ()
429
+ }
430
+ // TODO: This constraint is only the constraint imposed by the
431
+ // current project, not by any transitive deps. As a result,
432
+ // transitive project deps will always show "any" here.
433
+ bs .Constraint = c .Constraint
434
+
435
+ vl , err := sm .ListVersions (proj .Ident ())
436
+ if err == nil {
437
+ gps .SortPairedForUpgrade (vl )
438
+
439
+ for _ , v := range vl {
440
+ // Because we've sorted the version list for
441
+ // upgrade, the first version we encounter that
442
+ // matches our constraint will be what we want.
443
+ if c .Constraint .Matches (v ) {
444
+ bs .Latest = v .Revision ()
445
+ break
446
+ }
433
447
}
434
448
}
435
449
}
436
- }
437
450
438
- out .BasicLine (& bs )
451
+ bsCh <- & bs
452
+
453
+ }(proj )
439
454
}
455
+
456
+ wg .Wait ()
457
+ close (bsCh )
458
+ close (errorCh )
440
459
logger .Println ()
460
+
461
+ if len (errorCh ) > 0 {
462
+ for err := range errorCh {
463
+ ctx .Err .Println (err .Error ())
464
+ }
465
+ ctx .Err .Println ()
466
+ }
467
+
468
+ // A map of ProjectRoot and *BasicStatus. This is used in maintain the
469
+ // order of BasicStatus in output by collecting all the BasicStatus and
470
+ // then using them in order.
471
+ bsMap := make (map [string ]* BasicStatus )
472
+ for bs := range bsCh {
473
+ bsMap [bs .ProjectRoot ] = bs
474
+ }
475
+
476
+ // Use the collected BasicStatus in outputter
477
+ for _ , proj := range slp {
478
+ out .BasicLine (bsMap [string (proj .Ident ().ProjectRoot )])
479
+ }
480
+
441
481
out .BasicFooter ()
442
482
443
483
return digestMismatch , hasMissingPkgs , nil
0 commit comments