1 // goredo -- djb's redo implementation on pure Go
2 // Copyright (C) 2020-2024 Sergey Matveev <stargrave@stargrave.org>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
25 deps map[string]map[string]*Tgt,
28 if _, ok := DepCache[tgt.rel]; ok {
31 dep, err := depRead(tgt)
35 DepCache[tgt.rel] = dep
39 if dep.build == BuildUUID {
40 tracef(CDebug, "ood: %s%s always, but already build",
41 strings.Repeat(". ", level), tgt)
44 tracef(CDebug, "ood: %s%s always", strings.Repeat(". ", level), tgt)
45 alwayses = append(alwayses, tgt)
49 for _, ifchange := range dep.ifchanges {
50 if ifchange.tgt.rel == tgt.rel {
53 if !includeSrc && isSrc(ifchange.tgt) {
57 if m, ok := deps[ifchange.tgt.rel]; ok {
60 deps[ifchange.tgt.rel] = map[string]*Tgt{tgt.rel: tgt}
62 alwayses = append(alwayses,
63 collectDeps(ifchange.tgt, level+1, deps, includeSrc)...)
69 func buildDependants(tgts []*Tgt) map[string]*Tgt {
71 tracef(CDebug, "collecting deps")
72 seen := make(map[string]*Tgt)
73 deps := make(map[string]map[string]*Tgt)
74 for _, tgtInitial := range tgts {
75 for _, tgt := range collectDeps(tgtInitial, 0, deps, false) {
76 if tgt.rel != tgtInitial.rel {
81 TgtCache = make(map[string]*Tgt)
88 defer func() { Level = levelOrig }()
90 tracef(CDebug, "building %d alwayses: %v", len(seen), seen)
91 errs := make(chan error, len(seen))
93 okChecker := make(chan struct{})
95 for err := range errs {
96 ok = isOkRun(err) && ok
100 for _, tgt := range seen {
101 if err := runScript(tgt, errs, false, false); err != nil {
102 tracef(CErr, "always run error: %s, skipping dependants", err)
112 tracef(CDebug, "alwayses failed, skipping dependants")
116 queueSrc := make([]*Tgt, 0, len(seen))
117 for _, tgt := range seen {
118 queueSrc = append(queueSrc, tgt)
122 tracef(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc)
123 queue := make(map[string]*Tgt)
124 for _, tgt := range queueSrc {
125 for _, dep := range deps[tgt.rel] {
130 tracef(CDebug, "building %d dependant targets: %v", len(queue), queue)
131 errs = make(chan error, len(queue))
132 okChecker = make(chan struct{})
134 queueSrc = make([]*Tgt, 0)
136 for err := range errs {
137 ok = isOkRun(err) && ok
141 for _, tgt := range queue {
142 ood, err := isOODWithTrace(tgt, 0, seen)
144 tracef(CErr, "dependant error: %s, skipping dependants", err)
150 if err := runScript(tgt, errs, false, false); err != nil {
151 tracef(CErr, "dependant error: %s, skipping dependants", err)
154 queueSrc = append(queueSrc, tgt)
162 tracef(CDebug, "dependants failed, skipping them")
172 func ifchange(tgts []*Tgt, forced, traced bool) (bool, error) {
174 // only unique elements
175 m := make(map[string]*Tgt)
176 for _, t := range tgts {
180 for _, t := range m {
181 tgts = append(tgts, t)
187 defer jsAcquire("ifchange exiting")
189 seen := buildDependants(tgts)
195 tracef(CDebug, "building %d targets: %v", len(tgts), tgts)
199 okChecker := make(chan struct{})
200 errs := make(chan error, len(tgts))
202 for err := range errs {
203 ok = isOkRun(err) && ok
207 for _, tgt := range tgts {
208 if _, ok := seen[tgt.rel]; ok {
209 tracef(CDebug, "%s was already build as a dependant", tgt)
214 ood, err = isOODWithTrace(tgt, 0, seen)
218 return false, ErrLine(err)
225 tracef(CDebug, "%s is source, not redoing", tgt)
228 if err = runScript(tgt, errs, forced, traced); err != nil {
231 return false, ErrLine(err)