2 goredo -- redo implementation on pure Go
3 Copyright (C) 2020-2021 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 _, tgtInitial := range tgts {
87 for _, tgt := range collectDeps(Cwd, tgtInitial, 0, deps) {
88 if tgt != tgtInitial {
89 seen[tgt] = struct{}{}
102 trace(CDebug, "building %d alwayses: %v", len(seen), seen)
103 errs := make(chan error, len(seen))
104 for tgt := range seen {
105 if err := runScript(tgt, errs, false); err != nil {
106 trace(CErr, "always run error: %s, skipping dependants", err)
111 for i := 0; i < len(seen); i++ {
112 ok = ok && isOkRun(<-errs)
117 trace(CDebug, "alwayses failed, skipping dependants")
121 queueSrc := make([]string, 0, len(seen))
122 for tgt := range seen {
123 queueSrc = append(queueSrc, tgt)
125 if len(queueSrc) == 0 {
130 trace(CDebug, "checking %d dependant targets: %v", len(queueSrc), queueSrc)
132 for _, tgt := range queueSrc {
133 for dep := range deps[tgt] {
134 queue = append(queue, dep)
137 trace(CDebug, "building %d dependant targets: %v", len(queue), queue)
138 errs = make(chan error, len(queue))
140 queueSrc = []string{}
141 for _, tgt := range queue {
142 ood, err := isOOD(Cwd, tgt, 0, seen)
144 trace(CErr, "dependant error: %s, skipping dependants", err)
150 if err := runScript(tgt, errs, false); err != nil {
151 trace(CErr, "dependant error: %s, skipping dependants", err)
154 queueSrc = append(queueSrc, tgt)
155 seen[tgt] = struct{}{}
158 for i := 0; i < jobs; i++ {
159 ok = ok && isOkRun(<-errs)
162 trace(CDebug, "dependants failed, skipping them")
174 func ifchange(tgts []string, forced, traced bool) (bool, error) {
176 defer jsAcquire("ifchange exiting")
178 seen := buildDependants(tgts)
179 trace(CDebug, "building %d targets: %v", len(tgts), tgts)
181 errs := make(chan error, len(tgts))
184 for _, tgt := range tgts {
185 if _, ok := seen[tgt]; ok {
186 trace(CDebug, "%s was already build as a dependant", tgt)
191 ood, err = isOOD(Cwd, tgt, 0, seen)
200 trace(CDebug, "%s is source, not redoing", tgt)
203 if err = runScript(tgt, errs, traced); err != nil {
209 for ; jobs > 0; jobs-- {
210 ok = ok && isOkRun(<-errs)