.gitignore | 3 +++ doc/cmds.texi | 3 +++ doc/news.texi | 3 +++ main.go | 29 +++++++++++++++++++++++++++++ sources.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ targets.go | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++ usage.go | 14 +++++++++++++- diff --git a/.gitignore b/.gitignore index 21ac9e786dd84d34524ee02ae005fcd51e3ad6b508e291d89a74a471a253ca1c..1242a61859d60d000844c624029768a585b5a1d1e9a9c1077cce68a218b3760c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,10 @@ /redo-dot /redo-ifchange /redo-ifcreate /redo-log +/redo-ood +/redo-sources /redo-stamp +/redo-targets /redo-whichdo /tai64nlocal /VERSION diff --git a/doc/cmds.texi b/doc/cmds.texi index 77382374c04e3becf99352a9a76b88d9fd7095f0bb94b2a22a25cc5027152ead..fccadfa73448e27134e98ed0f371132f222a6278430920693defb0507d0e6f9c 100644 --- a/doc/cmds.texi +++ b/doc/cmds.texi @@ -13,6 +13,9 @@ @item redo-log Display @url{http://cr.yp.to/libtai/tai64.html, TAI64N} timestamped last @command{stderr} of the target. +@item redo-targets, redo-sources, redo-ood + List known targets, sources and out-of-date targets. + @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 beaeb9e4414063d295a98db03a5877ff459ad142c2f12562e0c7ddadb31780cb..b4bebb815ca7ea0b3037523d5e3a42e7c854a79504267c7c9f8f7f7d85e370fb 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -5,6 +5,9 @@ @anchor{Release 1.3.0} @section Release 1.3.0 @itemize @item + Experimental @command{redo-sources}, @command{redo-targets} and + @command{redo-ood} commands. +@item Repetitive OOD determination optimization: pass all already known to be OOD targets to redoing targets. @end itemize diff --git a/main.go b/main.go index 4271a669b29f14029a7a7233bc28093dad3e11661485bb99a2d438f891a37eab..f82ae65504651642eeb0f2cf05c13fc969e53ceb8fd28bfafa5b36566c59d683 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ "os" "path" "path/filepath" "runtime" + "sort" "strconv" "go.cypherpunks.ru/recfile" @@ -84,7 +85,10 @@ "redo-dot", "redo-ifchange", "redo-ifcreate", "redo-log", + "redo-ood", + "redo-sources", "redo-stamp", + "redo-targets", "redo-whichdo", } { fmt.Println(os.Args[0], "<-", cmdName) @@ -352,6 +356,31 @@ if err != nil { panic(err) } fmt.Println(rel) + } + case "redo-targets": + tgts, err = targetsWalker(Cwd) + sort.Strings(tgts) + for _, tgt := range tgts { + fmt.Println(tgt) + } + case "redo-ood": + tgts, err = targetsWalker(Cwd) + sort.Strings(tgts) + var ood bool + for _, tgt := range tgts { + ood, err = isOOD(Cwd, tgt, 0, nil) + if err != nil { + break + } + if ood { + fmt.Println(tgt) + } + } + case "redo-sources": + tgts, err = sourcesWalker() + sort.Strings(tgts) + for _, tgt := range tgts { + fmt.Println(tgt) } default: log.Fatalln("unknown command", cmdName) diff --git a/sources.go b/sources.go new file mode 100644 index 0000000000000000000000000000000000000000..3ff6367f47dcdce6b10299ff3244f15100f2c99f7873f268f0fd9ab1fbac09de --- /dev/null +++ b/sources.go @@ -0,0 +1,57 @@ +/* +goredo -- djb's redo implementation on pure Go +Copyright (C) 2020-2021 Sergey Matveev + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +package main + +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) + for _, tgt := range tgts { + cwd, f := path.Split(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)) + if err != nil { + panic(err) + } + srcs[cwdMustRel(pth)] = struct{}{} + } + } + } + tgts = make([]string, 0, len(srcs)) + for tgt := range srcs { + tgts = append(tgts, tgt) + } + return tgts, nil +} diff --git a/targets.go b/targets.go new file mode 100644 index 0000000000000000000000000000000000000000..03f42ddf04b784fc04c2220ed777d020f3520b9893ecc3a9dabd561ddd740276 --- /dev/null +++ b/targets.go @@ -0,0 +1,79 @@ +/* +goredo -- djb's redo implementation on pure Go +Copyright (C) 2020-2021 Sergey Matveev + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 3 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +package main + +import ( + "io" + "os" + "path" + "path/filepath" + "strings" +) + +func targetsWalker(root string) ([]string, error) { + root, err := filepath.Abs(root) + if err != nil { + panic(err) + } + dir, err := os.Open(root) + if err != nil { + return nil, 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 + } + for _, fi := range fis { + if !fi.IsDir() { + continue + } + pth := path.Join(root, fi.Name()) + if fi.Name() == RedoDir { + redoDir, err := os.Open(pth) + if err != nil { + return tgts, err + } + redoFis, err := redoDir.Readdir(0) + if err != nil { + return tgts, 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)]) + } + } + redoDir.Close() + } else { + subTgts, err := targetsWalker(pth) + tgts = append(tgts, subTgts...) + if err != nil { + return tgts, err + } + } + } + } + return tgts, dir.Close() +} diff --git a/usage.go b/usage.go index 852e9dbe73f98c3f24dec0550324c8680faf24b0f353dbf64b8135d7361631f2..c2b81331f42d9c40a90a6b2b6d1b98e8c2a63f91fb4414c32d7f35cdb50ff28f 100644 --- a/usage.go +++ b/usage.go @@ -86,6 +86,18 @@ d = `Usage: redo-whichdo 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 + +List all currently known targets.` + case "redo-sources": + d = `Usage: redo-sources + +List all currently known source files.` + case "redo-ood": + d = `Usage: redo-ood + +List all currently known out-of-date targets.` default: d = `Usage: goredo -symlinks @@ -93,7 +105,7 @@ 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.` } - fmt.Fprintf(os.Stderr, "%s\n\nOptions:\n", d) + fmt.Fprintf(os.Stderr, "%s\n\nCommon options:\n", d) flag.PrintDefaults() fmt.Fprintln(os.Stderr, ` Additional environment variables: