.gitignore | 1 + doc/cmds.texi | 3 +++ doc/news.texi | 8 ++++++++ ifchange.go | 15 +++++++++++---- main.go | 28 +++++++++++++++++++++++++++- targets.go | 13 ++++++++++++- usage.go | 12 ++++++++---- diff --git a/.gitignore b/.gitignore index 1242a61859d60d000844c624029768a585b5a1d1e9a9c1077cce68a218b3760c..a9ee8698bb3178b456759ab7f00597cd05e053dd4950d1b3cb905236d7c87353 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /goredo /redo +/redo-affects /redo-always /redo-cleanup /redo-dot diff --git a/doc/cmds.texi b/doc/cmds.texi index e143a468d2adfc8ea2ba0f125575e9db2481db19f1b6a48e0f2850868888bc39..0467e7c7f0f6526a1dafa065fb6b2d989bba22083bcee715be3510600c04d29d 100644 --- a/doc/cmds.texi +++ b/doc/cmds.texi @@ -19,6 +19,9 @@ results by specifying explicit targets you are interested in. @command{redo-sources} shows all recursive source files given targets depend on. +@item redo-affects + List all targets that will be affected by changing the specified ones. + @item redo-stamp Record stamp dependency. Nothing more, dummy. Read about @ref{Stamping, stamping} in the FAQ. diff --git a/doc/news.texi b/doc/news.texi index 981b45ca86ab2bb8d922d5188e259e59078a3eb0facf368b14c0ffd954021a46..e2190eea7bc5c87a0db499f70e9486efad847eb450840d6164aa971b4145b967 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -1,6 +1,14 @@ @node News @unnumbered News +@anchor{Release 1.6.0} +@section Release 1.6.0 +@itemize +@item + @command{redo-affects} command appeared, that shows all targets that + will be affected by changing the specified ones. +@end itemize + @anchor{Release 1.5.0} @section Release 1.5.0 @itemize diff --git a/ifchange.go b/ifchange.go index 733718932353675ad0d2baefd3deaf132b162da23a5cfd0b13adf83f3e4359c9..1ad18baa0b768967745461efd01fc1d9d17055b5477c203ee296ae15df38f767 100644 --- a/ifchange.go +++ b/ifchange.go @@ -27,6 +27,7 @@ func collectDeps( cwd, tgtOrig string, level int, deps map[string]map[string]struct{}, + includeSrc bool, ) []string { cwd, tgt := cwdAndTgt(path.Join(cwd, tgtOrig)) depPath := path.Join(cwd, RedoDir, tgt+DepSuffix) @@ -60,7 +61,10 @@ dep := m["Target"] if dep == "" { return alwayses } - if dep == tgt || isSrc(cwd, dep) { + if dep == tgt { + continue + } + if !includeSrc && isSrc(cwd, dep) { continue } if !returnReady { @@ -68,11 +72,14 @@ depRel := cwdMustRel(cwd, dep) if m, ok := deps[depRel]; ok { m[tgtRel] = struct{}{} } else { - m = make(map[string]struct{}, 0) + m = map[string]struct{}{} m[tgtRel] = struct{}{} deps[depRel] = m } - alwayses = append(alwayses, collectDeps(cwd, dep, level+1, deps)...) + alwayses = append( + alwayses, + collectDeps(cwd, dep, level+1, deps, includeSrc)..., + ) } } return alwayses @@ -84,7 +91,7 @@ trace(CDebug, "collecting deps") seen := map[string]struct{}{} deps := map[string]map[string]struct{}{} for _, tgtInitial := range tgts { - for _, tgt := range collectDeps(Cwd, tgtInitial, 0, deps) { + for _, tgt := range collectDeps(Cwd, tgtInitial, 0, deps, false) { if tgt != tgtInitial { seen[tgt] = struct{}{} } diff --git a/main.go b/main.go index 03ec8ab5bbd660e3507155cec665d7dc000a0e86506ae57743daea956ae17f94..862d2dde6b147366d11bc3b44b747ea8be3f18ea40123b1f90e0d7aa6e7681f6 100644 --- a/main.go +++ b/main.go @@ -79,6 +79,7 @@ if *symlinks { rc := 0 for _, cmdName := range []string{ "redo", + "redo-affects", "redo-always", "redo-cleanup", "redo-dot", @@ -197,7 +198,7 @@ if err != nil { panic(err) } unix.Flock(int(fdLock.Fd()), unix.LOCK_UN) - OODTgts = make(map[string]struct{}) + OODTgts = map[string]struct{}{} for _, tgtRaw := range bytes.Split(tgtsRaw, []byte{0}) { t := string(tgtRaw) if t == "" { @@ -370,6 +371,31 @@ } sort.Strings(tgts) for _, tgt := range tgts { fmt.Println(tgt) + } + case "redo-affects": + if tgtsWasEmpty { + log.Fatalln("no targets specified") + } + var tgtsKnown []string + tgtsKnown, err = targetsWalker([]string{Cwd}) + if err != nil { + break + } + deps := map[string]map[string]struct{}{} + for _, tgt := range tgtsKnown { + collectDeps(Cwd, tgt, 0, deps, true) + } + seen := map[string]struct{}{} + for _, tgt := range tgts { + collectWholeDeps(deps[tgt], deps, seen) + } + tgts := make([]string, 0, len(seen)) + for dep := range seen { + tgts = append(tgts, dep) + } + sort.Strings(tgts) + for _, dep := range tgts { + fmt.Println(dep) } case "redo-ood": if tgtsWasEmpty { diff --git a/targets.go b/targets.go index 19436ddbfcecbf6e247d988c27a92cbb0734ef555c043528c4d8b24350bc7dd6..b935a5912849ed82368df75628a9b7e5bf0bbe03ef13b387c3093f84b615cef1 100644 --- a/targets.go +++ b/targets.go @@ -76,7 +76,7 @@ return dir.Close() } func targetsWalker(tgts []string) ([]string, error) { - tgtsMap := make(map[string]struct{}, 0) + tgtsMap := map[string]struct{}{} for _, tgt := range tgts { if err := targetsCollect(tgt, tgtsMap); err != nil { return nil, err @@ -88,3 +88,14 @@ tgts = append(tgts, tgt) } return tgts, nil } + +func collectWholeDeps( + tgts map[string]struct{}, + deps map[string]map[string]struct{}, + seen map[string]struct{}, +) { + for tgt := range tgts { + seen[tgt] = struct{}{} + collectWholeDeps(deps[tgt], deps, seen) + } +} diff --git a/usage.go b/usage.go index 7a533840dd7d2a11669cd1a3752bcb0fd068fa4caec007d764f89a7c90965864..1f3a78f18cd3f7c9d94644094375846e42faae95b2e94175f231b5b51085acec 100644 --- a/usage.go +++ b/usage.go @@ -24,7 +24,7 @@ "os" ) const ( - Version = "1.5.0" + Version = "1.6.0" Warranty = `Copyright (C) 2020-2021 Sergey Matveev This program is free software: you can redistribute it and/or modify @@ -99,13 +99,17 @@ case "redo-ood": d = `Usage: redo-ood [target ...] List all currently known out-of-date targets.` + case "redo-affects": + d = `Usage: redo-affects target [...] + +List all targets that will be affected by changing the specified ones.` default: d = `Usage: goredo -symlinks goredo expects to be called through the symbolic link to it. -Available commands: redo, redo-always, redo-cleanup, redo-dot, -redo-ifchange, redo-ifcreate, redo-log, redo-ood, redo-sources, -redo-stamp, redo-targets, redo-whichdo.` +Available commands: redo, redo-affects, redo-always, redo-cleanup, +redo-dot, redo-ifchange, redo-ifcreate, redo-log, redo-ood, +redo-sources, redo-stamp, redo-targets, redo-whichdo.` } fmt.Fprintf(os.Stderr, "%s\n\nCommon options:\n", d) flag.PrintDefaults()