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 dep, err := depRead(tgt)
38 DepInfoCache[tgt.Dep()] = depInfo
39 seen[tgt.a] = struct{}{}
43 if dep.build == BuildUUID {
44 tracef(CDebug, "ood: %s%s always, but already build",
45 strings.Repeat(". ", level), tgt)
48 tracef(CDebug, "ood: %s%s always", strings.Repeat(". ", level), tgt)
49 alwayses = append(alwayses, tgt)
53 for _, ifchange := range dep.ifchanges {
54 if ifchange.tgt.rel == tgt.rel {
57 if !includeSrc && isSrc(ifchange.tgt) {
61 if m, ok := deps[ifchange.tgt.rel]; ok {
64 deps[ifchange.tgt.rel] = map[string]*Tgt{tgt.rel: tgt}
66 alwayses = append(alwayses,
67 collectDeps(dep.tgt, level+1, deps, includeSrc, seen)...)
73 func buildDependants(tgts []*Tgt) map[string]*Tgt {
75 tracef(CDebug, "collecting deps")
76 seen := make(map[string]*Tgt)
77 deps := make(map[string]map[string]*Tgt)
79 collectDepsSeen := make(map[string]struct{})
80 for _, tgtInitial := range tgts {
81 for _, tgt := range collectDeps(tgtInitial, 0, deps, false, collectDepsSeen) {
82 if tgt.a != tgtInitial.a {
87 InodeCache = make(map[string][]*Inode)
97 defer func() { Level = levelOrig }()
99 tracef(CDebug, "building %d alwayses: %v", len(seen), seen)
100 errs := make(chan error, len(seen))
102 okChecker := make(chan struct{})
104 for err := range errs {
105 ok = isOkRun(err) && ok
109 for _, tgt := range seen {
110 if err := runScript(tgt, errs, false, false); err != nil {
111 tracef(CErr, "always run error: %s, skipping dependants", err)
121 tracef(CDebug, "alwayses failed, skipping dependants")
125 queueSrc := make([]*Tgt, 0, len(seen))
126 for _, tgt := range seen {
127 queueSrc = append(queueSrc, tgt)
131 tracef(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc)
132 queue := make(map[string]*Tgt)
133 for _, tgt := range queueSrc {
134 for _, dep := range deps[tgt.rel] {
139 tracef(CDebug, "building %d dependant targets: %v", len(queue), queue)
140 errs = make(chan error, len(queue))
141 okChecker = make(chan struct{})
143 queueSrc = make([]*Tgt, 0)
145 for err := range errs {
146 ok = isOkRun(err) && ok
150 for _, tgt := range queue {
151 ood, err := isOODWithTrace(tgt, 0, seen)
153 tracef(CErr, "dependant error: %s, skipping dependants", err)
159 if err := runScript(tgt, errs, false, false); err != nil {
160 tracef(CErr, "dependant error: %s, skipping dependants", err)
163 queueSrc = append(queueSrc, tgt)
171 tracef(CDebug, "dependants failed, skipping them")
181 func ifchange(tgts []*Tgt, forced, traced bool) (bool, error) {
183 // only unique elements
184 m := make(map[string]*Tgt)
185 for _, t := range tgts {
189 for _, t := range m {
190 tgts = append(tgts, t)
196 defer jsAcquire("ifchange exiting")
198 seen := buildDependants(tgts)
204 tracef(CDebug, "building %d targets: %v", len(tgts), tgts)
208 okChecker := make(chan struct{})
209 errs := make(chan error, len(tgts))
211 for err := range errs {
212 ok = isOkRun(err) && ok
216 for _, tgt := range tgts {
217 if _, ok := seen[tgt.rel]; ok {
218 tracef(CDebug, "%s was already build as a dependant", tgt)
223 ood, err = isOODWithTrace(tgt, 0, seen)
227 return false, ErrLine(err)
234 tracef(CDebug, "%s is source, not redoing", tgt)
237 if err = runScript(tgt, errs, forced, traced); err != nil {
240 return false, ErrLine(err)