X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=main.go;h=a3773f43b3ce5b7dc96b09a1e52b5570ab084ba8;hb=eb14a3333a632b22a4b698ca28fea6e6d11048b8;hp=cd897720079423090d8e7dca9ad754dba162e2a4;hpb=a3d6bbf97e90bf923142d061bc68b28cc1dec2a8;p=goredo.git diff --git a/main.go b/main.go index cd89772..a3773f4 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,6 @@ /* -goredo -- redo implementation on pure Go -Copyright (C) 2020 Sergey Matveev +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 @@ -18,6 +18,8 @@ along with this program. If not, see . package main import ( + "bufio" + "bytes" "crypto/rand" "flag" "fmt" @@ -27,10 +29,12 @@ import ( "os" "path" "path/filepath" + "runtime" + "sort" "strconv" - "strings" "go.cypherpunks.ru/recfile" + "golang.org/x/sys/unix" ) var ( @@ -61,14 +65,14 @@ func main() { warranty := flag.Bool("warranty", false, "print warranty information") 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 { @@ -81,7 +85,10 @@ func main() { "redo-ifchange", "redo-ifcreate", "redo-log", + "redo-ood", + "redo-sources", "redo-stamp", + "redo-targets", "redo-whichdo", } { fmt.Println(os.Args[0], "<-", cmdName) @@ -97,11 +104,12 @@ func main() { var err error 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 == "" { @@ -112,6 +120,7 @@ func main() { panic(err) } } + DirPrefix = os.Getenv(EnvDirPrefix) if *flagStderrKeep { mustSetenv(EnvStderrKeep, "1") @@ -158,6 +167,46 @@ func main() { } // 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, io.SeekStart); 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) @@ -168,16 +217,18 @@ func main() { panic("negative " + EnvLevel) } } + var fdDep *os.File if v := os.Getenv(EnvDepFd); v != "" { fdDep = mustParseFd(v, EnvDepFd) } - BuildUUID = os.Getenv(EnvBuildUUID) + 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( @@ -188,6 +239,7 @@ func main() { tgts = []string{"all"} } } + statusInit() for i, tgt := range tgts { @@ -199,7 +251,10 @@ func main() { 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 { @@ -212,7 +267,9 @@ CmdSwitch: } case "redo-ifchange": ok, err = ifchange(tgts, false, traced) - writeDeps(fdDep, tgts) + if err == nil { + err = writeDeps(fdDep, tgts) + } case "redo-ifcreate": if fdDep == nil { log.Fatalln("no", EnvDepFd) @@ -258,18 +315,19 @@ CmdSwitch: 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()) + if err = os.Remove(fdTmp.Name()); err != nil { + break + } cwd, tgt := cwdAndTgt(tgts[0]) - cwdRel := cwdMustRel(cwd) doFile, upLevels, err := findDo(fdTmp, cwd, tgt) if err != nil { break } - _, err = fdTmp.Seek(0, 0) + _, err = fdTmp.Seek(0, io.SeekStart) if err != nil { break } @@ -287,7 +345,42 @@ CmdSwitch: if doFile == "" { ok = false } else { - fmt.Println(path.Join(cwdRel, strings.Repeat("..", upLevels), doFile)) + 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)