]> Cypherpunks.ru repositories - goredo.git/blobdiff - ifchange.go
Warn about several unsuccessful lock attempts
[goredo.git] / ifchange.go
index 43cfdb3e387e12474aec2034b719a8046ab6e6be..b3df3a8a34881bdffc45ff58f3e545358b6789cc 100644 (file)
@@ -1,6 +1,6 @@
 /*
 goredo -- djb's redo implementation on pure Go
-Copyright (C) 2020-2021 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2020-2023 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -98,7 +98,7 @@ func buildDependants(tgts []string) map[string]struct{} {
                }
        }
        if len(seen) == 0 {
-               return nil
+               return seen
        }
 
        levelOrig := Level
@@ -108,18 +108,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); err != nil {
+               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
@@ -135,17 +142,25 @@ func buildDependants(tgts []string) map[string]struct{} {
 
 RebuildDeps:
        tracef(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc)
-       queue := []string{}
+       queue := map[string]struct{}{}
        for _, tgt := range queueSrc {
                for dep := range deps[tgt] {
-                       queue = append(queue, dep)
+                       queue[dep] = struct{}{}
                }
        }
+
        tracef(CDebug, "building %d dependant targets: %v", len(queue), queue)
        errs = make(chan error, len(queue))
+       okChecker = make(chan struct{})
        jobs := 0
        queueSrc = []string{}
-       for _, tgt := range queue {
+       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 {
                        tracef(CErr, "dependant error: %s, skipping dependants", err)
@@ -154,7 +169,7 @@ RebuildDeps:
                if !ood {
                        continue
                }
-               if err := runScript(tgt, errs, false); err != nil {
+               if err := runScript(tgt, errs, false, false); err != nil {
                        tracef(CErr, "dependant error: %s, skipping dependants", err)
                        return nil
                }
@@ -162,15 +177,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
        }
@@ -179,18 +192,39 @@ RebuildDeps:
 }
 
 func ifchange(tgts []string, forced, traced bool) (bool, error) {
+       // only unique elements
+       m := make(map[string]struct{})
+       for _, t := range tgts {
+               m[t] = struct{}{}
+       }
+       tgts = tgts[:0]
+       for t := range m {
+               tgts = append(tgts, t)
+       }
+       m = nil
+
        jsInit()
        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)
@@ -200,6 +234,8 @@ func ifchange(tgts []string, forced, traced bool) (bool, error) {
                if !forced {
                        ood, err = isOODWithTrace(Cwd, tgt, 0, seen)
                        if err != nil {
+                               Jobs.Wait()
+                               close(errs)
                                return false, err
                        }
                }
@@ -210,14 +246,14 @@ func ifchange(tgts []string, forced, traced bool) (bool, error) {
                        tracef(CDebug, "%s is source, not redoing", tgt)
                        continue
                }
-               if err = runScript(tgt, errs, traced); err != nil {
+               if err = runScript(tgt, errs, forced, traced); err != nil {
+                       Jobs.Wait()
+                       close(errs)
                        return false, err
                }
-               jobs++
-       }
-       ok := true
-       for ; jobs > 0; jobs-- {
-               ok = isOkRun(<-errs) && ok
        }
+       Jobs.Wait()
+       close(errs)
+       <-okChecker
        return ok, nil
 }