@@ -429,7 +429,12 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana
429429 return false , 0 , errors .Wrapf (err , "could not set up solver for input hashing" )
430430 }
431431
432- cm := collectConstraints (ctx , p , sm )
432+ // Errors while collecting constraints should not fail the whole status run.
433+ // It should count the error and tell the user about incomplete results.
434+ cm , ccerrs := collectConstraints (ctx , p , sm )
435+ if len (ccerrs ) > 0 {
436+ errCount += len (ccerrs )
437+ }
433438
434439 // Get the project list and sort it so that the printed output users see is
435440 // deterministically ordered. (This may be superfluous if the lock is always
@@ -583,7 +588,7 @@ func runStatusAll(ctx *dep.Ctx, out outputter, p *dep.Project, sm gps.SourceMana
583588
584589 // Count ListVersions error because we get partial results when
585590 // this happens.
586- errCount = len (errListVerCh )
591+ errCount + = len (errListVerCh )
587592 if ctx .Verbose {
588593 for err := range errListVerCh {
589594 ctx .Err .Println (err .Error ())
@@ -712,37 +717,88 @@ type projectConstraint struct {
712717type constraintsCollection map [string ][]projectConstraint
713718
714719// collectConstraints collects constraints declared by all the dependencies.
715- func collectConstraints (ctx * dep.Ctx , p * dep.Project , sm gps.SourceManager ) constraintsCollection {
720+ // It returns constraintsCollection and a slice of errors encountered while
721+ // collecting the constraints, if any.
722+ func collectConstraints (ctx * dep.Ctx , p * dep.Project , sm gps.SourceManager ) (constraintsCollection , []error ) {
723+ logger := ctx .Err
724+ if ! ctx .Verbose {
725+ logger = log .New (ioutil .Discard , "" , 0 )
726+ }
727+
728+ logger .Println ("Collecting project constraints:" )
729+
730+ var mutex sync.Mutex
716731 constraintCollection := make (constraintsCollection )
717732
718733 // Get direct deps of the root project.
719734 _ , directDeps , err := getDirectDependencies (sm , p )
720735 if err != nil {
721- ctx .Err .Println ("Error getting direct deps:" , err )
736+ // Return empty collection, not nil, if we fail here.
737+ return constraintCollection , []error {errors .Wrap (err , "failed to get direct dependencies" )}
722738 }
739+
723740 // Create a root analyzer.
724741 rootAnalyzer := newRootAnalyzer (true , ctx , directDeps , sm )
725742
743+ lp := p .Lock .Projects ()
744+
745+ // Channel for receiving all the errors.
746+ errCh := make (chan error , len (lp ))
747+
748+ var wg sync.WaitGroup
749+
726750 // Iterate through the locked projects and collect constraints of all the projects.
727- for _ , proj := range p .Lock .Projects () {
728- manifest , _ , err := sm .GetManifestAndLock (proj .Ident (), proj .Version (), rootAnalyzer )
729- if err != nil {
730- ctx .Err .Println ("Error getting manifest and lock:" , err )
731- continue
732- }
751+ for i , proj := range lp {
752+ wg .Add (1 )
753+ logger .Printf ("(%d/%d) %s\n " , i + 1 , len (lp ), proj .Ident ().ProjectRoot )
754+
755+ go func (proj gps.LockedProject ) {
756+ defer wg .Done ()
757+
758+ manifest , _ , err := sm .GetManifestAndLock (proj .Ident (), proj .Version (), rootAnalyzer )
759+ if err != nil {
760+ errCh <- errors .Wrap (err , "error getting manifest and lock" )
761+ return
762+ }
733763
734- // Get project constraints.
735- pc := manifest .DependencyConstraints ()
764+ // Get project constraints.
765+ pc := manifest .DependencyConstraints ()
766+
767+ // Obtain a lock for constraintCollection.
768+ mutex .Lock ()
769+ defer mutex .Unlock ()
770+ // Iterate through the project constraints to get individual dependency
771+ // project and constraint values.
772+ for pr , pp := range pc {
773+ tempCC := append (
774+ constraintCollection [string (pr )],
775+ projectConstraint {proj .Ident ().ProjectRoot , pp .Constraint },
776+ )
777+
778+ // Sort the inner projectConstraint slice by Project string.
779+ // Required for consistent returned value.
780+ sort .Sort (byProject (tempCC ))
781+ constraintCollection [string (pr )] = tempCC
782+ }
783+ }(proj )
784+ }
785+
786+ wg .Wait ()
787+ close (errCh )
736788
737- // Iterate through the project constraints to get individual dependency
738- // project and constraint values.
739- for pr , pp := range pc {
740- constraintCollection [string (pr )] = append (
741- constraintCollection [string (pr )],
742- projectConstraint {proj .Ident ().ProjectRoot , pp .Constraint },
743- )
789+ var errs []error
790+ if len (errCh ) > 0 {
791+ for e := range errCh {
792+ errs = append (errs , e )
793+ logger .Println (e .Error ())
744794 }
745795 }
746796
747- return constraintCollection
797+ return constraintCollection , errs
748798}
799+
800+ type byProject []projectConstraint
801+
802+ func (p byProject ) Len () int { return len (p ) }
803+ func (p byProject ) Swap (i , j int ) { p [i ], p [j ] = p [j ], p [i ] }
804+ func (p byProject ) Less (i , j int ) bool { return p [i ].Project > p [j ].Project }
0 commit comments