2 goredo -- djb's redo implementation on pure Go
3 Copyright (C) 2020-2023 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 deps map[string]map[string]*Tgt,
29 seen map[string]struct{},
31 if _, ok := seen[tgt.a]; ok {
34 depInfo, err := depRead(tgt)
38 seen[tgt.a] = struct{}{}
42 if depInfo.build == BuildUUID {
44 CDebug, "ood: %s%s always, but already build",
45 strings.Repeat(". ", level), tgt,
49 tracef(CDebug, "ood: %s%s always", strings.Repeat(". ", level), tgt)
50 alwayses = append(alwayses, tgt)
54 for _, dep := range depInfo.ifchanges {
55 if dep.tgt.a == tgt.a {
58 if !includeSrc && isSrc(dep.tgt) {
62 if m, ok := deps[dep.tgt.a]; ok {
65 deps[dep.tgt.a] = map[string]*Tgt{tgt.a: tgt}
67 alwayses = append(alwayses,
68 collectDeps(dep.tgt, level+1, deps, includeSrc, seen)...)
74 func buildDependants(tgts []*Tgt) map[string]*Tgt {
76 tracef(CDebug, "collecting deps")
77 seen := make(map[string]*Tgt)
78 deps := make(map[string]map[string]*Tgt)
80 collectDepsSeen := make(map[string]struct{})
81 for _, tgtInitial := range tgts {
82 for _, tgt := range collectDeps(tgtInitial, 0, deps, false, collectDepsSeen) {
83 if tgt.a != tgtInitial.a {
94 defer func() { Level = levelOrig }()
96 tracef(CDebug, "building %d alwayses: %v", len(seen), seen)
97 errs := make(chan error, len(seen))
99 okChecker := make(chan struct{})
101 for err := range errs {
102 ok = isOkRun(err) && ok
106 for _, tgt := range seen {
107 if err := runScript(tgt, errs, false, false); err != nil {
108 tracef(CErr, "always run error: %s, skipping dependants", err)
118 tracef(CDebug, "alwayses failed, skipping dependants")
122 queueSrc := make([]*Tgt, 0, len(seen))
123 for _, tgt := range seen {
124 queueSrc = append(queueSrc, tgt)
128 tracef(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc)
129 queue := make(map[string]*Tgt)
130 for _, tgt := range queueSrc {
131 for _, dep := range deps[tgt.a] {
136 tracef(CDebug, "building %d dependant targets: %v", len(queue), queue)
137 errs = make(chan error, len(queue))
138 okChecker = make(chan struct{})
140 queueSrc = make([]*Tgt, 0)
142 for err := range errs {
143 ok = isOkRun(err) && ok
147 for _, tgt := range queue {
148 ood, err := isOODWithTrace(tgt, 0, seen)
150 tracef(CErr, "dependant error: %s, skipping dependants", err)
156 if err := runScript(tgt, errs, false, false); err != nil {
157 tracef(CErr, "dependant error: %s, skipping dependants", err)
160 queueSrc = append(queueSrc, tgt)
168 tracef(CDebug, "dependants failed, skipping them")
178 func ifchange(tgts []*Tgt, forced, traced bool) (bool, error) {
180 // only unique elements
181 m := make(map[string]*Tgt)
182 for _, t := range tgts {
186 for _, t := range m {
187 tgts = append(tgts, t)
193 defer jsAcquire("ifchange exiting")
195 seen := buildDependants(tgts)
201 tracef(CDebug, "building %d targets: %v", len(tgts), tgts)
205 okChecker := make(chan struct{})
206 errs := make(chan error, len(tgts))
208 for err := range errs {
209 ok = isOkRun(err) && ok
213 for _, tgt := range tgts {
214 if _, ok := seen[tgt.a]; ok {
215 tracef(CDebug, "%s was already build as a dependant", tgt)
220 ood, err = isOODWithTrace(tgt, 0, seen)
224 return false, ErrLine(err)
231 tracef(CDebug, "%s is source, not redoing", tgt)
234 if err = runScript(tgt, errs, forced, traced); err != nil {
237 return false, ErrLine(err)