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 DepInfoCache[tgt.Dep()] = depInfo
39 seen[tgt.a] = struct{}{}
43 if depInfo.build == BuildUUID {
45 CDebug, "ood: %s%s always, but already build",
46 strings.Repeat(". ", level), tgt,
50 tracef(CDebug, "ood: %s%s always", strings.Repeat(". ", level), tgt)
51 alwayses = append(alwayses, tgt)
55 for _, dep := range depInfo.ifchanges {
56 if dep.tgt.a == tgt.a {
59 if !includeSrc && isSrc(dep.tgt) {
63 if m, ok := deps[dep.tgt.a]; ok {
66 deps[dep.tgt.a] = map[string]*Tgt{tgt.a: tgt}
68 alwayses = append(alwayses,
69 collectDeps(dep.tgt, level+1, deps, includeSrc, seen)...)
75 func buildDependants(tgts []*Tgt) map[string]*Tgt {
77 tracef(CDebug, "collecting deps")
78 seen := make(map[string]*Tgt)
79 deps := make(map[string]map[string]*Tgt)
81 collectDepsSeen := make(map[string]struct{})
82 for _, tgtInitial := range tgts {
83 for _, tgt := range collectDeps(tgtInitial, 0, deps, false, collectDepsSeen) {
84 if tgt.a != tgtInitial.a {
89 InodeCache = make(map[string][]*Inode)
99 defer func() { Level = levelOrig }()
101 tracef(CDebug, "building %d alwayses: %v", len(seen), seen)
102 errs := make(chan error, len(seen))
104 okChecker := make(chan struct{})
106 for err := range errs {
107 ok = isOkRun(err) && ok
111 for _, tgt := range seen {
112 if err := runScript(tgt, errs, false, false); err != nil {
113 tracef(CErr, "always run error: %s, skipping dependants", err)
123 tracef(CDebug, "alwayses failed, skipping dependants")
127 queueSrc := make([]*Tgt, 0, len(seen))
128 for _, tgt := range seen {
129 queueSrc = append(queueSrc, tgt)
133 tracef(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc)
134 queue := make(map[string]*Tgt)
135 for _, tgt := range queueSrc {
136 for _, dep := range deps[tgt.a] {
141 tracef(CDebug, "building %d dependant targets: %v", len(queue), queue)
142 errs = make(chan error, len(queue))
143 okChecker = make(chan struct{})
145 queueSrc = make([]*Tgt, 0)
147 for err := range errs {
148 ok = isOkRun(err) && ok
152 for _, tgt := range queue {
153 ood, err := isOODWithTrace(tgt, 0, seen)
155 tracef(CErr, "dependant error: %s, skipping dependants", err)
161 if err := runScript(tgt, errs, false, false); err != nil {
162 tracef(CErr, "dependant error: %s, skipping dependants", err)
165 queueSrc = append(queueSrc, tgt)
173 tracef(CDebug, "dependants failed, skipping them")
183 func ifchange(tgts []*Tgt, forced, traced bool) (bool, error) {
185 // only unique elements
186 m := make(map[string]*Tgt)
187 for _, t := range tgts {
191 for _, t := range m {
192 tgts = append(tgts, t)
198 defer jsAcquire("ifchange exiting")
200 seen := buildDependants(tgts)
206 tracef(CDebug, "building %d targets: %v", len(tgts), tgts)
210 okChecker := make(chan struct{})
211 errs := make(chan error, len(tgts))
213 for err := range errs {
214 ok = isOkRun(err) && ok
218 for _, tgt := range tgts {
219 if _, ok := seen[tgt.a]; ok {
220 tracef(CDebug, "%s was already build as a dependant", tgt)
225 ood, err = isOODWithTrace(tgt, 0, seen)
229 return false, ErrLine(err)
236 tracef(CDebug, "%s is source, not redoing", tgt)
239 if err = runScript(tgt, errs, forced, traced); err != nil {
242 return false, ErrLine(err)