]> Cypherpunks.ru repositories - goredo.git/blobdiff - ifchange.go
DRY filepath.Abs/Rel
[goredo.git] / ifchange.go
index 401574de816b8ef06d7af2c2210917326823807d..0b8d694ff730023e71d4dcb2d3314fe84a5328b0 100644 (file)
@@ -28,8 +28,13 @@ func collectDeps(
        level int,
        deps map[string]map[string]struct{},
        includeSrc bool,
+       seen map[string]struct{},
 ) []string {
        cwd, tgt := cwdAndTgt(path.Join(cwd, tgtOrig))
+       tgtFull := path.Join(cwd, tgt)
+       if _, ok := seen[tgtFull]; ok {
+               return nil
+       }
        depPath := path.Join(cwd, RedoDir, tgt+DepSuffix)
        fdDep, err := os.Open(depPath)
        if err != nil {
@@ -40,6 +45,7 @@ func collectDeps(
        if err != nil {
                return nil
        }
+       seen[tgtFull] = struct{}{}
        var alwayses []string
        returnReady := false
        tgtRel := cwdMustRel(cwd, tgt)
@@ -76,10 +82,8 @@ func collectDeps(
                                m[tgtRel] = struct{}{}
                                deps[depRel] = m
                        }
-                       alwayses = append(
-                               alwayses,
-                               collectDeps(cwd, dep, level+1, deps, includeSrc)...,
-                       )
+                       alwayses = append(alwayses,
+                               collectDeps(cwd, dep, level+1, deps, includeSrc, seen)...)
                }
        }
        return alwayses
@@ -90,8 +94,9 @@ func buildDependants(tgts []string) map[string]struct{} {
        tracef(CDebug, "collecting deps")
        seen := map[string]struct{}{}
        deps := map[string]map[string]struct{}{}
+       collectDepsSeen := make(map[string]struct{})
        for _, tgtInitial := range tgts {
-               for _, tgt := range collectDeps(Cwd, tgtInitial, 0, deps, false) {
+               for _, tgt := range collectDeps(Cwd, tgtInitial, 0, deps, false, collectDepsSeen) {
                        if tgt != tgtInitial {
                                seen[tgt] = struct{}{}
                        }
@@ -100,6 +105,7 @@ func buildDependants(tgts []string) map[string]struct{} {
        if len(seen) == 0 {
                return seen
        }
+       collectDepsSeen = nil
 
        levelOrig := Level
        defer func() {
@@ -108,18 +114,25 @@ func buildDependants(tgts []string) map[string]struct{} {
        Level = 1
        tracef(CDebug, "building %d alwayses: %v", len(seen), seen)
        errs := make(chan error, len(seen))
+       ok := true
+       okChecker := make(chan struct{})
+       go func() {
+               for err := range errs {
+                       ok = isOkRun(err) && ok
+               }
+               close(okChecker)
+       }()
        for tgt := range seen {
                if err := runScript(tgt, errs, false, false); err != nil {
                        tracef(CErr, "always run error: %s, skipping dependants", err)
+                       Jobs.Wait()
+                       close(errs)
                        return nil
                }
        }
-       ok := true
-       for i := 0; i < len(seen); i++ {
-               ok = isOkRun(<-errs) && ok
-       }
        Jobs.Wait()
        close(errs)
+       <-okChecker
        if !ok {
                tracef(CDebug, "alwayses failed, skipping dependants")
                return nil
@@ -144,8 +157,15 @@ RebuildDeps:
 
        tracef(CDebug, "building %d dependant targets: %v", len(queue), queue)
        errs = make(chan error, len(queue))
+       okChecker = make(chan struct{})
        jobs := 0
        queueSrc = []string{}
+       go func() {
+               for err := range errs {
+                       ok = isOkRun(err) && ok
+               }
+               close(okChecker)
+       }()
        for tgt := range queue {
                ood, err := isOODWithTrace(Cwd, tgt, 0, seen)
                if err != nil {
@@ -163,15 +183,13 @@ RebuildDeps:
                seen[tgt] = struct{}{}
                jobs++
        }
-       for i := 0; i < jobs; i++ {
-               ok = isOkRun(<-errs) && ok
-       }
+       Jobs.Wait()
+       close(errs)
+       <-okChecker
        if !ok {
                tracef(CDebug, "dependants failed, skipping them")
                return nil
        }
-       Jobs.Wait()
-       close(errs)
        if jobs == 0 {
                return seen
        }
@@ -195,17 +213,24 @@ func ifchange(tgts []string, forced, traced bool) (bool, error) {
        if !IsTopRedo {
                defer jsAcquire("ifchange exiting")
        }
-       defer Jobs.Wait()
        seen := buildDependants(tgts)
        if seen == nil {
+               Jobs.Wait()
                return false, nil
        }
        oodTgtsClear()
        tracef(CDebug, "building %d targets: %v", len(tgts), tgts)
-       jobs := 0
-       errs := make(chan error, len(tgts))
        var ood bool
        var err error
+       ok := true
+       okChecker := make(chan struct{})
+       errs := make(chan error, len(tgts))
+       go func() {
+               for err := range errs {
+                       ok = isOkRun(err) && ok
+               }
+               close(okChecker)
+       }()
        for _, tgt := range tgts {
                if _, ok := seen[tgt]; ok {
                        tracef(CDebug, "%s was already build as a dependant", tgt)
@@ -215,7 +240,9 @@ func ifchange(tgts []string, forced, traced bool) (bool, error) {
                if !forced {
                        ood, err = isOODWithTrace(Cwd, tgt, 0, seen)
                        if err != nil {
-                               return false, err
+                               Jobs.Wait()
+                               close(errs)
+                               return false, ErrLine(err)
                        }
                }
                if !ood {
@@ -226,13 +253,13 @@ func ifchange(tgts []string, forced, traced bool) (bool, error) {
                        continue
                }
                if err = runScript(tgt, errs, forced, traced); err != nil {
-                       return false, err
+                       Jobs.Wait()
+                       close(errs)
+                       return false, ErrLine(err)
                }
-               jobs++
-       }
-       ok := true
-       for ; jobs > 0; jobs-- {
-               ok = isOkRun(<-errs) && ok
        }
+       Jobs.Wait()
+       close(errs)
+       <-okChecker
        return ok, nil
 }