/*
-goredo -- redo implementation on pure Go
-Copyright (C) 2020 Sergey Matveev <stargrave@stargrave.org>
+goredo -- djb's redo implementation on pure Go
+Copyright (C) 2020-2021 Sergey Matveev <stargrave@stargrave.org>
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
import (
"bufio"
+ "bytes"
"crypto/rand"
"flag"
"fmt"
"os"
"path"
"path/filepath"
+ "runtime"
+ "sort"
"strconv"
"go.cypherpunks.ru/recfile"
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 direcotyr")
+ symlinks := flag.Bool("symlinks", false, "create necessary symlinks in current directory")
- flag.Usage = usage
+ flag.Usage = func() { usage(os.Args[0]) }
flag.Parse()
if *warranty {
fmt.Println(Warranty)
return
}
if *version {
- fmt.Println(versionGet())
+ fmt.Println("goredo", Version, "built with", runtime.Version())
return
}
if *symlinks {
"redo-ifchange",
"redo-ifcreate",
"redo-log",
+ "redo-ood",
+ "redo-sources",
"redo-stamp",
+ "redo-targets",
"redo-whichdo",
} {
fmt.Println(os.Args[0], "<-", cmdName)
log.Println(err)
}
}
- fmt.Println("no creating optional:", os.Args[0], "<- tai64nlocal")
os.Exit(rc)
}
log.SetFlags(0)
var err error
- Cwd, err = unix.Getwd()
+ Cwd, err = os.Getwd()
if err != nil {
- panic(err)
+ log.Fatalln(err)
}
NoColor = os.Getenv(EnvNoColor) != ""
NoSync = os.Getenv(EnvNoSync) == "1"
+ InodeTrust = os.Getenv(EnvInodeNoTrust) == ""
TopDir = os.Getenv(EnvTopDir)
- if TopDir != "" {
+ if TopDir == "" {
+ TopDir = "/"
+ } else {
TopDir, err = filepath.Abs(TopDir)
if err != nil {
panic(err)
}
}
+ DirPrefix = os.Getenv(EnvDirPrefix)
if *flagStderrKeep {
mustSetenv(EnvStderrKeep, "1")
if *flagStderrSilent {
mustSetenv(EnvStderrSilent, "1")
}
+ if *flagNoProgress {
+ mustSetenv(EnvNoProgress, "1")
+ }
if *flagDebug {
mustSetenv(EnvDebug, "1")
}
}
StderrKeep = os.Getenv(EnvStderrKeep) == "1"
StderrSilent = os.Getenv(EnvStderrSilent) == "1"
+ NoProgress = os.Getenv(EnvNoProgress) == "1"
Debug = os.Getenv(EnvDebug) == "1"
LogWait = os.Getenv(EnvLogWait) == "1"
LogLock = os.Getenv(EnvLogLock) == "1"
if Debug || os.Getenv(EnvLogPid) == "1" {
MyPid = os.Getpid()
}
+ var traced bool
+ if *flagTraceAll {
+ mustSetenv(EnvTrace, "1")
+ }
if *flagTrace {
- Trace = true
+ traced = true
} else {
- Trace = os.Getenv(EnvTrace) == "1"
+ traced = os.Getenv(EnvTrace) == "1"
}
// Those are internal envs
+ FdOODTgts, err = ioutil.TempFile("", "ood-tgts")
+ if err != nil {
+ panic(err)
+ }
+ if err = os.Remove(FdOODTgts.Name()); err != nil {
+ panic(err)
+ }
+ FdOODTgtsLock, err = ioutil.TempFile("", "ood-tgts.lock")
+ if err != nil {
+ panic(err)
+ }
+ if err = os.Remove(FdOODTgtsLock.Name()); err != nil {
+ panic(err)
+ }
+
+ if v := os.Getenv(EnvOODTgtsFd); v != "" {
+ fd := mustParseFd(v, EnvOODTgtsFd)
+ fdLock := mustParseFd(v, EnvOODTgtsLockFd)
+ if err = unix.Flock(int(fdLock.Fd()), unix.LOCK_EX); err != nil {
+ panic(err)
+ }
+ if _, err = fd.Seek(0, os.SEEK_SET); err != nil {
+ panic(err)
+ }
+ tgtsRaw, err := ioutil.ReadAll(bufio.NewReader(fd))
+ if err != nil {
+ panic(err)
+ }
+ unix.Flock(int(fdLock.Fd()), unix.LOCK_UN)
+ OODTgts = make(map[string]struct{})
+ for _, tgtRaw := range bytes.Split(tgtsRaw, []byte{0}) {
+ t := string(tgtRaw)
+ if t == "" {
+ continue
+ }
+ OODTgts[t] = struct{}{}
+ trace(CDebug, "ood: known to be: %s", t)
+ }
+ }
+
StderrPrefix = os.Getenv(EnvStderrPrefix)
if v := os.Getenv(EnvLevel); v != "" {
Level, err = strconv.Atoi(v)
panic("negative " + EnvLevel)
}
}
+
var fdDep *os.File
if v := os.Getenv(EnvDepFd); v != "" {
fdDep = mustParseFd(v, EnvDepFd)
}
+
+ tgts := flag.Args()
BuildUUID = os.Getenv(EnvBuildUUID)
if BuildUUID == "" {
raw := new([16]byte)
if _, err = io.ReadFull(rand.Reader, raw[:]); err != nil {
- panic(err)
+ log.Fatalln(err)
}
raw[6] = (raw[6] & 0x0F) | uint8(4<<4) // version 4
BuildUUID = fmt.Sprintf(
"%x-%x-%x-%x-%x",
raw[0:4], raw[4:6], raw[6:8], raw[8:10], raw[10:],
)
+ if len(tgts) == 0 {
+ tgts = []string{"all"}
+ }
}
- tgts := flag.Args()
- if len(tgts) == 0 {
- tgts = []string{"all"}
+ statusInit()
+
+ for i, tgt := range tgts {
+ if path.IsAbs(tgt) {
+ tgts[i] = cwdMustRel(tgt)
+ }
}
+
ok := true
err = nil
cmdName := path.Base(os.Args[0])
- trace(CDebug, "[%s] run: %s %s [%s]", BuildUUID, cmdName, tgts, Cwd)
+ trace(
+ CDebug, "[%s] run: %s %s cwd:%s dirprefix:%s",
+ BuildUUID, cmdName, tgts, Cwd, DirPrefix,
+ )
CmdSwitch:
switch cmdName {
case "redo":
for _, tgt := range tgts {
- ok, err = ifchange([]string{tgt}, true)
+ ok, err = ifchange([]string{tgt}, true, traced)
if err != nil || !ok {
break
}
}
case "redo-ifchange":
- ok, err = ifchange(tgts, false)
- writeDeps(fdDep, tgts)
+ ok, err = ifchange(tgts, false, traced)
+ if err == nil {
+ err = writeDeps(fdDep, tgts)
+ }
case "redo-ifcreate":
if fdDep == nil {
log.Fatalln("no", EnvDepFd)
log.Fatalln("single target expected")
}
var fdTmp *os.File
- fdTmp, err = ioutil.TempFile("", "")
+ fdTmp, err = ioutil.TempFile("", "whichdo")
if err != nil {
break
}
- os.Remove(fdTmp.Name())
- var doFile string
+ if err = os.Remove(fdTmp.Name()); err != nil {
+ break
+ }
cwd, tgt := cwdAndTgt(tgts[0])
- doFile, _, err = findDo(fdTmp, cwd, tgt)
+ doFile, upLevels, err := findDo(fdTmp, cwd, tgt)
if err != nil {
break
}
- _, err = fdTmp.Seek(0, 0)
+ _, err = fdTmp.Seek(0, os.SEEK_SET)
if err != nil {
break
}
}
fmt.Println(cwdMustRel(cwd, m["Target"]))
}
- ok = doFile != ""
- case "tai64nlocal":
- bw := bufio.NewWriter(os.Stdout)
- err = tai64nLocal(bw, os.Stdin)
- bw.Flush()
+ if doFile == "" {
+ ok = false
+ } else {
+ p := make([]string, 0, upLevels+2)
+ p = append(p, cwd)
+ for i := 0; i < upLevels; i++ {
+ p = append(p, "..")
+ }
+ p = append(p, doFile)
+ rel, err := filepath.Rel(Cwd, path.Join(p...))
+ 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)
}