cleanup.go | 11 ++++++++--- doc/cmds.texi | 6 +++--- doc/news.texi | 15 +++++++++++++++ js.go | 11 ++++++++++- log.go | 25 ++++++++++++++++++++----- main.go | 107 +++++++++++++++++++++++++++++++++-------------------- run.go | 22 ++++++++++++++++++---- status.go | 10 +++++++++- usage.go | 41 ++++++++++++++++++++++------------------- diff --git a/cleanup.go b/cleanup.go index b2dce227b24d88cd07408f0a48a1e1fee9040136b26cc853ce497825c75dd333..6fdf3373b8318a25466004aa2c4e2aa3b2ab4c08dc4cb9fc29e94ae091218476 100644 --- a/cleanup.go +++ b/cleanup.go @@ -34,9 +34,14 @@ CleanupLog = "log" CleanupTmp = "tmp" ) -var ( - DryRun = flag.Bool("dry-run", false, "do no delete files during cleanup, just show them") -) +var DryRun *bool + +func init() { + if CmdName() != CmdNameRedoCleanup { + return + } + DryRun = flag.Bool("n", false, "do no delete files during cleanup, just show them") +} func redoDirClean(root, what string) error { root, err := filepath.Abs(root) diff --git a/doc/cmds.texi b/doc/cmds.texi index 444aed6c3336421c82c7d205ff2fa617e4a34eb24c0cb719b0ad51e786758225..25da63e0b7b2de51c5d85817ef400e539020ed6a99e26f276211aa692533a1fd 100644 --- a/doc/cmds.texi +++ b/doc/cmds.texi @@ -31,14 +31,14 @@ With @option{-j} option you can enable parallel builds, probably with an infinite number of workers (@code{=0}). Also you can set @env{$REDO_JOBS} to automatically apply that setting globally. -With @option{-logs} (@env{$REDO_LOGS=1}) option you can capture job's +With @option{-k} (@env{$REDO_LOGS=1}) option you can capture job's @code{stderr} on the disk and read it later with @command{redo-log} command. Log's lines have @url{http://cr.yp.to/libtai/tai64.html, TAI64N} timestamp. You can decode it with @command{tai64nlocal} utility from @url{http://cr.yp.to/daemontools.html, daemontools}, or similar one: @code{go get go.cypherpunks.ru/tai64n/cmd/tai64nlocal}. -@option{-silent} (@env{$REDO_SILENT=1}) omits @code{stderr} printing at -all, but you can still capture it with @option{-logs}. +@option{-s} (@env{$REDO_SILENT=1}) omits @code{stderr} printing at +all, but you can still capture it with @option{-k}. @option{-log-pid} (@env{$REDO_LOG_PID=1}) can be used to prefix job's @code{stderr} with the PID, that could be useful during parallel builds. diff --git a/doc/news.texi b/doc/news.texi index 2c7a8e6a7549d28dab3c0b199384737168ff9eaf7fd4e66a85911e00b9221fc9..f3759a68758ce32a232793be1e5911dbe8c84b5d3e70066b0b225b6937821070 100644 --- a/doc/news.texi +++ b/doc/news.texi @@ -1,6 +1,21 @@ @node News @unnumbered News +@anchor{Release 1.9.0} +@section Release 1.9.0 +@itemize +@item + Do not enable command lines options not applicable to the command. + For example @option{-j} option is only applicable to @command{redo} + and @command{redo-ifchange} commands. +@item + @itemize + @item @option{-dry-run} option is renamed to @option{-n} + @item @option{-logs} option is renamed to @option{-k} + @item @option{-silent} option is renamed to @option{-s} + @end itemize +@end itemize + @anchor{Release 1.8.0} @section Release 1.8.0 @itemize diff --git a/js.go b/js.go index 9a902a4f2865a56a5468ac9dd4b06c83cdcb67f6e87793ae020ca6d81d383873..4ab392a8f3dc174e575c052e8a5ca96e6eefd0d2e1e1389c4cc3e12ecba59724 100644 --- a/js.go +++ b/js.go @@ -69,8 +69,17 @@ jsToken byte // got via EnvJSToken jsTokens map[byte]int jsTokensM sync.Mutex - flagJobs = flag.Int("j", -1, fmt.Sprintf("number of parallel jobs (0=inf, <0=1) (%s)", EnvJobs)) + flagJobs *int ) + +func init() { + cmdName := CmdName() + if !(cmdName == CmdNameRedo || cmdName == CmdNameRedoIfchange) { + return + } + flagJobs = flag.Int("j", -1, + fmt.Sprintf("number of parallel jobs (0=inf, <0=1) (%s)", EnvJobs)) +} func jsStart(jobsEnv string) { jobs := uint64(1) diff --git a/log.go b/log.go index 3ebe81b7e1b136758adf6dc965a22f436b38f64cb9c3a51330b676d1fcd07681..2f74f912278928b9e6fda6a171f738f6081a59492d3d88610f9a5b02f28d909e 100644 --- a/log.go +++ b/log.go @@ -61,12 +61,12 @@ CJS string CReset string CNone string = "NONE" - flagNoProgress = flag.Bool("no-progress", false, fmt.Sprintf("no progress printing (%s=1), also implies -no-status", EnvNoProgress)) flagDebug = flag.Bool("d", false, fmt.Sprintf("enable debug logging (%s=1)", EnvDebug)) - flagLogWait = flag.Bool("log-wait", false, fmt.Sprintf("enable wait messages logging (%s=1)", EnvLogWait)) - flagLogLock = flag.Bool("log-lock", false, fmt.Sprintf("enable lock messages logging (%s=1)", EnvLogLock)) - flagLogPid = flag.Bool("log-pid", false, fmt.Sprintf("append PIDs (%s=1)", EnvLogPid)) - flagLogJS = flag.Bool("log-js", false, fmt.Sprintf("enable jobserver messages logging (%s=1)", EnvLogJS)) + flagNoProgress *bool + flagLogWait *bool + flagLogLock *bool + flagLogPid *bool + flagLogJS *bool LogMutex sync.Mutex KeyEraseLine string @@ -84,6 +84,21 @@ CWarn = string(t.Escape.Magenta) CJS = string(t.Escape.White) CReset = string(t.Escape.Reset) KeyEraseLine = fmt.Sprintf("%s[K", CReset[0:1]) + + cmdName := CmdName() + if !(cmdName == CmdNameRedo || cmdName == CmdNameRedoIfchange) { + return + } + flagNoProgress = flag.Bool("no-progress", false, + fmt.Sprintf("no progress printing (%s=1), also implies -no-status", EnvNoProgress)) + flagLogWait = flag.Bool("log-wait", false, + fmt.Sprintf("enable wait messages logging (%s=1)", EnvLogWait)) + flagLogLock = flag.Bool("log-lock", false, + fmt.Sprintf("enable lock messages logging (%s=1)", EnvLogLock)) + flagLogPid = flag.Bool("log-pid", false, + fmt.Sprintf("append PIDs (%s=1)", EnvLogPid)) + flagLogJS = flag.Bool("log-js", false, + fmt.Sprintf("enable jobserver messages logging (%s=1)", EnvLogJS)) } func erasedStatus(s, end string) string { diff --git a/main.go b/main.go index 74d7d5d65224ba616137ee9ebf4a090081202847b96a1a74537b2ffa05e25ef8..41bb719ca248695ff572d6336a6db40a3d88d3095232d3a9592fdedd6d33a5e7 100644 --- a/main.go +++ b/main.go @@ -37,6 +37,23 @@ "go.cypherpunks.ru/recfile" "golang.org/x/sys/unix" ) +const ( + CmdNameGoredo = "goredo" + CmdNameRedo = "redo" + CmdNameRedoAffects = "redo-affects" + CmdNameRedoAlways = "redo-always" + CmdNameRedoCleanup = "redo-cleanup" + CmdNameRedoDot = "redo-dot" + CmdNameRedoIfchange = "redo-ifchange" + CmdNameRedoIfcreate = "redo-ifcreate" + CmdNameRedoLog = "redo-log" + CmdNameRedoOOD = "redo-ood" + CmdNameRedoSources = "redo-sources" + CmdNameRedoStamp = "redo-stamp" + CmdNameRedoTargets = "redo-targets" + CmdNameRedoWhichdo = "redo-whichdo" +) + var ( Cwd string BuildUUID string @@ -61,10 +78,19 @@ } return fd } +func CmdName() string { + return path.Base(os.Args[0]) +} + func main() { version := flag.Bool("version", false, "print version") warranty := flag.Bool("warranty", false, "print warranty information") - symlinks := flag.Bool("symlinks", false, "create necessary symlinks in current directory") + + var symlinks *bool + cmdName := CmdName() + if cmdName == "goredo" { + symlinks = flag.Bool("symlinks", false, "create necessary symlinks in current directory") + } flag.Usage = func() { usage(os.Args[0]) } flag.Parse() @@ -76,22 +102,22 @@ if *version { fmt.Println("goredo", Version, "built with", runtime.Version()) return } - if *symlinks { + if cmdName == CmdNameGoredo && *symlinks { rc := 0 for _, cmdName := range []string{ - "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", + CmdNameRedo, + CmdNameRedoAffects, + CmdNameRedoAlways, + CmdNameRedoCleanup, + CmdNameRedoDot, + CmdNameRedoIfchange, + CmdNameRedoIfcreate, + CmdNameRedoLog, + CmdNameRedoOOD, + CmdNameRedoSources, + CmdNameRedoStamp, + CmdNameRedoTargets, + CmdNameRedoWhichdo, } { fmt.Println(os.Args[0], "<-", cmdName) if err := os.Symlink(os.Args[0], cmdName); err != nil { @@ -125,28 +151,28 @@ } DirPrefix = os.Getenv(EnvDirPrefix) DepCwd = os.Getenv(EnvDepCwd) - if *flagStderrKeep { + if flagStderrKeep != nil && *flagStderrKeep { mustSetenv(EnvStderrKeep, "1") } - if *flagStderrSilent { + if flagStderrSilent != nil && *flagStderrSilent { mustSetenv(EnvStderrSilent, "1") } - if *flagNoProgress { + if flagNoProgress != nil && *flagNoProgress { mustSetenv(EnvNoProgress, "1") } - if *flagDebug { + if flagDebug != nil && *flagDebug { mustSetenv(EnvDebug, "1") } - if *flagLogWait { + if flagLogWait != nil && *flagLogWait { mustSetenv(EnvLogWait, "1") } - if *flagLogLock { + if flagLogLock != nil && *flagLogLock { mustSetenv(EnvLogLock, "1") } - if *flagLogPid { + if flagLogPid != nil && *flagLogPid { mustSetenv(EnvLogPid, "1") } - if *flagLogJS { + if flagLogJS != nil && *flagLogJS { mustSetenv(EnvLogJS, "1") } StderrKeep = os.Getenv(EnvStderrKeep) == "1" @@ -160,13 +186,13 @@ if Debug || os.Getenv(EnvLogPid) == "1" { MyPid = os.Getpid() } var traced bool - if *flagTraceAll { + if flagTraceAll != nil && *flagTraceAll { mustSetenv(EnvTrace, "1") } if os.Getenv(EnvTrace) == "1" { TracedAll = true traced = true - } else { + } else if flagTrace != nil { traced = *flagTrace } @@ -246,7 +272,9 @@ tgts = []string{"all"} } } - statusInit() + if cmdName == CmdNameRedo || cmdName == CmdNameRedoIfchange { + statusInit() + } for i, tgt := range tgts { if path.IsAbs(tgt) { @@ -256,7 +284,6 @@ } ok := true err = nil - cmdName := path.Base(os.Args[0]) trace( CDebug, "[%s] run: %s %s cwd:%s dirprefix:%s", BuildUUID, cmdName, tgts, Cwd, DirPrefix, @@ -264,19 +291,19 @@ ) CmdSwitch: switch cmdName { - case "redo": + case CmdNameRedo: for _, tgt := range tgts { ok, err = ifchange([]string{tgt}, true, traced) if err != nil || !ok { break } } - case "redo-ifchange": + case CmdNameRedoIfchange: ok, err = ifchange(tgts, false, traced) if err == nil { err = writeDeps(fdDep, tgts) } - case "redo-ifcreate": + case CmdNameRedoIfcreate: if fdDep == nil { log.Fatalln("no", EnvDepFd) } @@ -286,26 +313,26 @@ if err != nil { break } } - case "redo-always": + case CmdNameRedoAlways: if fdDep == nil { log.Fatalln("no", EnvDepFd) } err = always(fdDep) - case "redo-cleanup": + case CmdNameRedoCleanup: for _, what := range tgts { err = cleanupWalker(Cwd, what) if err != nil { break } } - case "redo-dot": + case CmdNameRedoDot: err = dotPrint(tgts) - case "redo-stamp": + case CmdNameRedoStamp: if fdDep == nil { log.Fatalln("no", EnvDepFd) } err = stamp(fdDep, os.Stdin) - case "redo-log": + case CmdNameRedoLog: if len(tgts) != 1 { log.Fatalln("single target expected") } @@ -316,7 +343,7 @@ if err != nil { break } _, err = io.Copy(os.Stdout, fd) - case "redo-whichdo": + case CmdNameRedoWhichdo: if len(tgts) != 1 { log.Fatalln("single target expected") } @@ -363,7 +390,7 @@ panic(err) } fmt.Println(rel) } - case "redo-targets": + case CmdNameRedoTargets: if tgtsWasEmpty { tgts = []string{Cwd} } @@ -375,7 +402,7 @@ sort.Strings(tgts) for _, tgt := range tgts { fmt.Println(tgt) } - case "redo-affects": + case CmdNameRedoAffects: if tgtsWasEmpty { log.Fatalln("no targets specified") } @@ -400,7 +427,7 @@ sort.Strings(tgts) for _, dep := range tgts { fmt.Println(dep) } - case "redo-ood": + case CmdNameRedoOOD: if tgtsWasEmpty { tgts, err = targetsWalker([]string{Cwd}) if err != nil { @@ -418,7 +445,7 @@ if ood { fmt.Println(tgt) } } - case "redo-sources": + case CmdNameRedoSources: if tgtsWasEmpty { tgts, err = targetsWalker([]string{Cwd}) if err != nil { diff --git a/run.go b/run.go index 63d489080e16b62d325998d0f616d5e09e012b31e808571a34b7c0294f3c6c96..1c379b9156b3458a539a55c373d6a6c11c5365543334d94aaac1c9494d76961d 100644 --- a/run.go +++ b/run.go @@ -64,13 +64,27 @@ StderrSilent bool = false StderrPrefix string Jobs sync.WaitGroup - flagTrace = flag.Bool("x", false, "trace (sh -x) current targets") - flagTraceAll = flag.Bool("xx", false, fmt.Sprintf("trace (sh -x) all targets (%s=1)", EnvTrace)) - flagStderrKeep = flag.Bool("logs", false, fmt.Sprintf("keep job's stderr (%s=1)", EnvStderrKeep)) - flagStderrSilent = flag.Bool("silent", false, fmt.Sprintf("do not print job's stderr (%s=1)", EnvStderrSilent)) + flagTrace *bool + flagTraceAll *bool + flagStderrKeep *bool + flagStderrSilent *bool TracedAll bool ) + +func init() { + cmdName := CmdName() + if !(cmdName == CmdNameRedo || cmdName == CmdNameRedoIfchange) { + return + } + flagTrace = flag.Bool("x", false, "trace (sh -x) current targets") + flagTraceAll = flag.Bool("xx", false, + fmt.Sprintf("trace (sh -x) all targets (%s=1)", EnvTrace)) + flagStderrKeep = flag.Bool("k", false, + fmt.Sprintf("keep job's stderr (%s=1)", EnvStderrKeep)) + flagStderrSilent = flag.Bool("s", false, + fmt.Sprintf("silent, do not print job's stderr (%s=1)", EnvStderrSilent)) +} type RunErr struct { Tgt string diff --git a/status.go b/status.go index d0146f6622e1d877ec615c81c42d3f7925e618febf9e2c7c25895efc87916800..2811f954b22ac8f9f50e95cb98058c1f9bcdc968605e5fe79c9bbaae92b1bd09 100644 --- a/status.go +++ b/status.go @@ -37,8 +37,16 @@ var ( FdStatus *os.File - flagNoStatus = flag.Bool("no-status", false, "disable statusline (REDO_NO_STATUS=1)") + flagNoStatus *bool ) + +func init() { + cmdName := CmdName() + if !(cmdName == CmdNameRedo || cmdName == CmdNameRedoIfchange) { + return + } + flagNoStatus = flag.Bool("no-status", false, "disable statusline (REDO_NO_STATUS=1)") +} func statusInit() { if NoProgress || *flagNoStatus { diff --git a/usage.go b/usage.go index 43db2324ce5294ac84fa4f2b06184e9a2c12827d154c50c47f3544c74ce19954..1fd0fe65f8b313b153eb7b5e4d34b07fa463815dc75423e1f810794206127846 100644 --- a/usage.go +++ b/usage.go @@ -24,7 +24,7 @@ "os" ) const ( - Version = "1.8.0" + Version = "1.9.0" Warranty = `Copyright (C) 2020-2021 Sergey Matveev This program is free software: you can redistribute it and/or modify @@ -43,63 +43,63 @@ func usage(cmd string) { var d string switch cmd { - case "redo": - d = `Usage: redo [options] [target ...] + case CmdNameRedo: + d = `Usage: redo [-j X] [-k] [-s] [-x|-xx] [options] [target ...] Forcefully and *sequentially* build specified targets. If no targets specified, then use "all" one.` - case "redo-ifchange": - d = `Usage: redo-ifchange target [...] + case CmdNameRedoIfchange: + d = `Usage: redo-ifchange [-j X] [-k] [-s] [-x|-xx] target [...] Build specified targets in parallel, if they are changed. Record them as dependencies for current target.` - case "redo-ifcreate": + case CmdNameRedoIfcreate: d = `Usage: redo-ifcreate target [...] Record ifcreate dependency for current target. Unusable outside .do.` - case "redo-always": + case CmdNameRedoAlways: d = `Usage: redo-always Always build current target. Unusable outside .do.` - case "redo-cleanup": - d = `Usage: redo-cleanup [-dry-run] {full,log,tmp} [...] + case CmdNameRedoCleanup: + d = `Usage: redo-cleanup [-n] {full,log,tmp} [...] Remove either all goredo's related temporary files, or kept stderr logs, or everything (including .redo directories) related.` - case "redo-log": + case CmdNameRedoLog: d = `Usage: redo-log target [ | tai64nlocal ] Display kept target's stderr with TAI64N timestamped lines. Only the last build is kept. You must enable stderr keeping with either -logs, or REDO_LOGS=1.` - case "redo-dot": + case CmdNameRedoDot: d = `Usage: redo-dot target [...] Write dependency DOT graph to stdout.` - case "redo-stamp": + case CmdNameRedoStamp: d = `Usage: redo-stamp < [$3] Record stamp dependency for current target. Unusable outside .do. Stamp dependency does not play any role, as all targets are hashed anyway.` - case "redo-whichdo": + case CmdNameRedoWhichdo: 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": + case CmdNameRedoTargets: d = `Usage: redo-targets [target ...] List all currently known targets.` - case "redo-sources": + case CmdNameRedoSources: d = `Usage: redo-sources [target ...] List all currently known source files.` - case "redo-ood": + case CmdNameRedoOOD: d = `Usage: redo-ood [target ...] List all currently known out-of-date targets.` - case "redo-affects": + case CmdNameRedoAffects: d = `Usage: redo-affects target [...] List all targets that will be affected by changing the specified ones.` @@ -116,10 +116,13 @@ flag.PrintDefaults() fmt.Fprintln(os.Stderr, ` Additional environment variables: NO_COLOR -- disable messages colouring + REDO_TOP_DIR -- do not search for .do above that directory + (it can contain .redo/top as an alternative)`) + if cmd == CmdNameRedo || cmd == CmdNameRedoIfchange { + fmt.Fprintln(os.Stderr, ` REDO_NO_SYNC -- disable files/directories explicit filesystem syncing - REDO_TOP_DIR -- do not search for .do above that directory - (it can contain .redo/top as an alternative) REDO_INODE_NO_TRUST -- do not trust inode information (except for size) and always check file's hash REDO_MAKE -- bmake/gmake/none(default) jobserver protocol compatibility`) + } }