@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
@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
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 {
"%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"}
}
}
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 {
}
}
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)
"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
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
}
"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() {
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
}
)
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
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 [...]
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:
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()