2 goredo -- redo implementation on pure Go
3 Copyright (C) 2020 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/>.
29 deps map[string]map[string]struct{},
31 cwd, tgt := cwdAndTgt(path.Join(cwd, tgtOrig))
32 depPath := path.Join(cwd, RedoDir, tgt+DepSuffix)
33 fdDep, err := os.Open(depPath)
37 depInfo, err := depRead(fdDep)
44 tgtRel := cwdMustRel(cwd, tgt)
46 if depInfo.build == BuildUUID {
48 CDebug, "ood: %s%s always, but already build",
49 strings.Repeat(". ", level), tgtOrig,
53 trace(CDebug, "ood: %s%s always", strings.Repeat(". ", level), tgtOrig)
54 alwayses = append(alwayses, tgtRel)
58 for _, m := range depInfo.ifchanges {
63 if dep == tgt || isSrc(cwd, dep) {
67 depRel := cwdMustRel(cwd, dep)
68 if m, ok := deps[depRel]; ok {
69 m[tgtRel] = struct{}{}
71 m = make(map[string]struct{}, 0)
72 m[tgtRel] = struct{}{}
75 alwayses = append(alwayses, collectDeps(cwd, dep, level+1, deps)...)
81 func buildDependants(tgts []string) map[string]struct{} {
83 trace(CDebug, "collecting deps")
84 seen := map[string]struct{}{}
85 deps := map[string]map[string]struct{}{}
86 for _, tgt := range tgts {
87 for _, tgt := range collectDeps(Cwd, tgt, 0, deps) {
88 seen[tgt] = struct{}{}
100 trace(CDebug, "building %d alwayses: %v", len(seen), seen)
101 errs := make(chan error, len(seen))
102 for tgt, _ := range seen {
103 if err := runScript(tgt, errs, false); err != nil {
104 trace(CErr, "always run error: %s, skipping dependants", err)
109 for i := 0; i < len(seen); i++ {
110 ok = ok && isOkRun(<-errs)
115 trace(CDebug, "alwayses failed, skipping depdendants")
119 queueSrc := make([]string, 0, len(seen))
120 for tgt, _ := range seen {
121 queueSrc = append(queueSrc, tgt)
123 if len(queueSrc) == 0 {
128 trace(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc)
130 for _, tgt := range queueSrc {
131 for dep, _ := range deps[tgt] {
132 queue = append(queue, dep)
135 trace(CDebug, "building %d dependant targets: %v", len(queue), queue)
136 errs = make(chan error, len(queue))
138 queueSrc = []string{}
139 for _, tgt := range queue {
140 ood, err := isOOD(Cwd, tgt, 0, seen)
142 trace(CErr, "dependant error: %s, skipping dependants", err)
148 if err := runScript(tgt, errs, false); err != nil {
149 trace(CErr, "dependant error: %s, skipping dependants", err)
152 queueSrc = append(queueSrc, tgt)
153 seen[tgt] = struct{}{}
156 for i := 0; i < jobs; i++ {
157 ok = ok && isOkRun(<-errs)
160 trace(CDebug, "dependants failed, skipping them")
172 func ifchange(tgts []string, forced, traced bool) (bool, error) {
174 defer jsAcquire("ifchange exiting")
176 seen := buildDependants(tgts)
177 trace(CDebug, "building %d targets: %v", len(tgts), tgts)
179 errs := make(chan error, len(tgts))
182 for _, tgt := range tgts {
183 if _, ok := seen[tgt]; ok {
184 trace(CDebug, "%s was already build as a dependenant", tgt)
189 ood, err = isOOD(Cwd, tgt, 0, seen)
198 trace(CDebug, "%s is source, not redoing", tgt)
201 if err = runScript(tgt, errs, traced); err != nil {
207 for ; jobs > 0; jobs-- {
208 ok = ok && isOkRun(<-errs)