// goredo -- djb's redo implementation on pure Go // Copyright (C) 2020-2024 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 ( "flag" "fmt" "log" "os" ) const ( EnvStatusFd = "REDO_STATUS_FD" EnvNoStatus = "REDO_NO_STATUS" StatusRun = iota StatusDone StatusWait StatusWaited ) var ( FdStatus *os.File 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 { return } if v := os.Getenv(EnvNoStatus); v == "1" { return } if v := os.Getenv(EnvStatusFd); v != "" { if v == "NO" { return } FdStatus = mustParseFd(v, EnvStatusFd) return } var r *os.File var err error r, FdStatus, err = os.Pipe() if err != nil { log.Fatal(err) } go func() { running := 0 waiting := 0 done := 0 var out string buf := make([]byte, 1) var n int for { n, err = r.Read(buf) if err != nil || n != 1 { break } switch buf[0] { case StatusRun: running++ case StatusDone: running-- done++ case StatusWait: waiting++ case StatusWaited: waiting-- } if NoColor { out = fmt.Sprintf( "\rrun: %d wait: %d done: %d", running, waiting, done, ) } else { out = fmt.Sprintf( "\rrun: %s%d%s wait: %s%d%s done: %s%d%s", CRedo, running, CReset, CWait, waiting, CReset, CJS, done, CReset, ) } out = erasedStatus(out, "\r") LogMutex.Lock() os.Stderr.WriteString(out) LogMutex.Unlock() } }() }