From ca5290c19761bc1806b98d54d966a9cbbfeabd15 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Tue, 22 Jun 2021 10:47:27 +0300 Subject: [PATCH] redo-affects --- .gitignore | 1 + doc/cmds.texi | 3 +++ doc/news.texi | 8 ++++++++ ifchange.go | 15 +++++++++++---- main.go | 28 +++++++++++++++++++++++++++- targets.go | 13 ++++++++++++- usage.go | 12 ++++++++---- 7 files changed, 70 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index dcf061d..60a3ad6 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 578d182..6e5fc2f 100644 --- a/doc/cmds.texi +++ b/doc/cmds.texi @@ -19,6 +19,9 @@ @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 c2674ae..d301bdd 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 1f2c381..0f430fd 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 @@ func collectDeps( 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 @@ func collectDeps( 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 @@ func buildDependants(tgts []string) map[string]struct{} { 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 092d389..8c9c16d 100644 --- a/main.go +++ b/main.go @@ -79,6 +79,7 @@ func main() { rc := 0 for _, cmdName := range []string{ "redo", + "redo-affects", "redo-always", "redo-cleanup", "redo-dot", @@ -197,7 +198,7 @@ func main() { 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 == "" { @@ -371,6 +372,31 @@ CmdSwitch: 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 { tgts, err = targetsWalker([]string{Cwd}) diff --git a/targets.go b/targets.go index bc8edfd..0545483 100644 --- a/targets.go +++ b/targets.go @@ -76,7 +76,7 @@ func targetsCollect(root string, tgts map[string]struct{}) error { } 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 @@ func targetsWalker(tgts []string) ([]string, error) { } 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 670da2a..b18c93b 100644 --- a/usage.go +++ b/usage.go @@ -24,7 +24,7 @@ import ( ) 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 @@ List all currently known source files.` 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() -- 2.44.0