From cb183690cc59ad772dab941adc3e9b8d5b90fbc0 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Mon, 21 Jun 2021 15:56:07 +0300 Subject: [PATCH] Recursively search for all sources. Ability to narrow results --- doc/cmds.texi | 7 +++++-- doc/news.texi | 14 ++++++++++++++ main.go | 32 ++++++++++++++++++++++++++------ sources.go | 39 +++++++++++++++++++++++---------------- targets.go | 35 +++++++++++++++++++++++------------ usage.go | 14 ++++++++------ 6 files changed, 99 insertions(+), 42 deletions(-) diff --git a/doc/cmds.texi b/doc/cmds.texi index d0e93c3..578d182 100644 --- a/doc/cmds.texi +++ b/doc/cmds.texi @@ -11,10 +11,13 @@ @item redo-log Display @url{http://cr.yp.to/libtai/tai64.html, TAI64N} timestamped - last @command{stderr} of the target. + last @command{stderr} of the target, captured before. @item redo-targets, redo-sources, redo-ood - List known targets, sources and out-of-date targets. + List known targets, sources and out-of-date targets. You can limit + results by specifying explicit targets you are interested in. + @command{redo-sources} shows all recursive source files given + targets depend on. @item redo-stamp Record stamp dependency. Nothing more, dummy. Read about diff --git a/doc/news.texi b/doc/news.texi index 36f6aa9..c2674ae 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -1,6 +1,20 @@ @node News @unnumbered News +@anchor{Release 1.5.0} +@section Release 1.5.0 +@itemize +@item + @command{redo-ood}, @command{redo-sources} and + @command{redo-targets} can optionally take list of targets to apply + the command on, to narrow the result. +@item + @command{redo-sources} mistakenly missed @file{.do} files in the output. +@item + @command{redo-sources} now recursively searches for all source + files, not the "first" depth level ones. +@end itemize + @anchor{Release 1.4.1} @section Release 1.4.1 @itemize diff --git a/main.go b/main.go index f6668c2..092d389 100644 --- a/main.go +++ b/main.go @@ -226,6 +226,7 @@ func main() { tgts := flag.Args() BuildUUID = os.Getenv(EnvBuildUUID) + tgtsWasEmpty := len(tgts) == 0 if BuildUUID == "" { raw := new([16]byte) if _, err = io.ReadFull(rand.Reader, raw[:]); err != nil { @@ -236,7 +237,7 @@ func main() { "%x-%x-%x-%x-%x", raw[0:4], raw[4:6], raw[6:8], raw[8:10], raw[10:], ) - if len(tgts) == 0 { + if tgtsWasEmpty { tgts = []string{"all"} } } @@ -359,13 +360,24 @@ CmdSwitch: fmt.Println(rel) } case "redo-targets": - tgts, err = targetsWalker(Cwd) + if tgtsWasEmpty { + tgts = []string{Cwd} + } + tgts, err = targetsWalker(tgts) + if err != nil { + break + } sort.Strings(tgts) for _, tgt := range tgts { fmt.Println(tgt) } case "redo-ood": - tgts, err = targetsWalker(Cwd) + if tgtsWasEmpty { + tgts, err = targetsWalker([]string{Cwd}) + if err != nil { + break + } + } sort.Strings(tgts) var ood bool for _, tgt := range tgts { @@ -378,10 +390,18 @@ CmdSwitch: } } case "redo-sources": - tgts, err = sourcesWalker() + if tgtsWasEmpty { + tgts, err = targetsWalker([]string{Cwd}) + if err != nil { + break + } + } sort.Strings(tgts) - for _, tgt := range tgts { - fmt.Println(tgt) + var srcs []string + srcs, err = sourcesWalker(tgts) + sort.Strings(srcs) + for _, src := range srcs { + fmt.Println(src) } default: log.Fatalln("unknown command", cmdName) diff --git a/sources.go b/sources.go index e321c43..0d36190 100644 --- a/sources.go +++ b/sources.go @@ -21,17 +21,16 @@ import ( "os" "path" "path/filepath" - "strings" ) -func sourcesWalker() ([]string, error) { - tgts, err := targetsWalker(Cwd) - if err != nil { - return nil, err - } - srcs := make(map[string]struct{}, 1<<10) +func sourcesWalker(tgts []string) ([]string, error) { + seen := make(map[string]struct{}, 1<<10) for _, tgt := range tgts { - cwd, f := path.Split(tgt) + tgtAbsPath, err := filepath.Abs(path.Join(Cwd, tgt)) + if err != nil { + panic(err) + } + cwd, f := path.Split(path.Join(Cwd, tgt)) fdDep, err := os.Open(path.Join(cwd, RedoDir, f+DepSuffix)) if err != nil { return nil, err @@ -39,19 +38,27 @@ func sourcesWalker() ([]string, error) { depInfo, err := depRead(fdDep) fdDep.Close() for _, m := range depInfo.ifchanges { - tgt = m["Target"] - if !strings.HasSuffix(tgt, ".do") && isSrc(cwd, tgt) { - pth, err := filepath.Abs(path.Join(cwd, tgt)) + depTgt := m["Target"] + depTgtAbsPath, err := filepath.Abs(path.Join(cwd, depTgt)) + if err != nil { + panic(err) + } + if isSrc(cwd, depTgt) { + seen[cwdMustRel(depTgtAbsPath)] = struct{}{} + } else if depTgtAbsPath != tgtAbsPath { + subSrcs, err := sourcesWalker([]string{cwdMustRel(depTgtAbsPath)}) if err != nil { panic(err) } - srcs[cwdMustRel(pth)] = struct{}{} + for _, p := range subSrcs { + seen[p] = struct{}{} + } } } } - tgts = make([]string, 0, len(srcs)) - for tgt := range srcs { - tgts = append(tgts, tgt) + srcs := make([]string, 0, len(seen)) + for p := range seen { + srcs = append(srcs, p) } - return tgts, nil + return srcs, nil } diff --git a/targets.go b/targets.go index 602fd94..bc8edfd 100644 --- a/targets.go +++ b/targets.go @@ -25,24 +25,23 @@ import ( "strings" ) -func targetsWalker(root string) ([]string, error) { +func targetsCollect(root string, tgts map[string]struct{}) error { root, err := filepath.Abs(root) if err != nil { panic(err) } dir, err := os.Open(root) if err != nil { - return nil, err + return err } defer dir.Close() - tgts := make([]string, 0, 1<<10) for { fis, err := dir.Readdir(1 << 10) if err != nil { if err == io.EOF { break } - return tgts, err + return err } for _, fi := range fis { if !fi.IsDir() { @@ -52,28 +51,40 @@ func targetsWalker(root string) ([]string, error) { if fi.Name() == RedoDir { redoDir, err := os.Open(pth) if err != nil { - return tgts, err + return err } redoFis, err := redoDir.Readdir(0) if err != nil { - return tgts, err + return err } for _, redoFi := range redoFis { name := redoFi.Name() if strings.HasSuffix(name, DepSuffix) { name = cwdMustRel(root, name) - tgts = append(tgts, name[:len(name)-len(DepSuffix)]) + tgts[name[:len(name)-len(DepSuffix)]] = struct{}{} } } redoDir.Close() } else { - subTgts, err := targetsWalker(pth) - tgts = append(tgts, subTgts...) - if err != nil { - return tgts, err + if err = targetsCollect(pth, tgts); err != nil { + return err } } } } - return tgts, dir.Close() + return dir.Close() +} + +func targetsWalker(tgts []string) ([]string, error) { + tgtsMap := make(map[string]struct{}, 0) + for _, tgt := range tgts { + if err := targetsCollect(tgt, tgtsMap); err != nil { + return nil, err + } + } + tgts = make([]string, 0, len(tgtsMap)) + for tgt := range tgtsMap { + tgts = append(tgts, tgt) + } + return tgts, nil } diff --git a/usage.go b/usage.go index 81e954d..670da2a 100644 --- a/usage.go +++ b/usage.go @@ -24,7 +24,7 @@ import ( ) const ( - Version = "1.4.1" + Version = "1.5.0" Warranty = `Copyright (C) 2020-2021 Sergey Matveev This program is free software: you can redistribute it and/or modify @@ -46,7 +46,8 @@ func usage(cmd string) { case "redo": d = `Usage: redo [options] [target ...] -Forcefully and *sequentially* build specified targets.` +Forcefully and *sequentially* build specified targets. +If no targets specified, then use "all" one.` case "redo-ifchange": d = `Usage: redo-ifchange target [...] @@ -87,15 +88,15 @@ anyway.` Display .do search paths for specified target. Exits successfully if the last .do in output if the found existing one.` case "redo-targets": - d = `Usage: redo-targets + d = `Usage: redo-targets [target ...] List all currently known targets.` case "redo-sources": - d = `Usage: redo-sources + d = `Usage: redo-sources [target ...] List all currently known source files.` case "redo-ood": - d = `Usage: redo-ood + d = `Usage: redo-ood [target ...] List all currently known out-of-date targets.` default: @@ -103,7 +104,8 @@ List all currently known out-of-date targets.` 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-stamp, redo-whichdo.` +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