/*
goredo -- djb's redo implementation on pure Go
-Copyright (C) 2020-2021 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2020-2023 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
"flag"
"fmt"
"io"
- "io/ioutil"
"log"
"os"
"os/signal"
CmdNameRedoStamp = "redo-stamp"
CmdNameRedoTargets = "redo-targets"
CmdNameRedoWhichdo = "redo-whichdo"
+ CmdNameRedoDepFix = "redo-depfix"
+ CmdNameRedoInode = "redo-inode"
)
var (
Cwd string
BuildUUID string
IsTopRedo bool // is it the top redo instance
+ UmaskCur int
)
func mustSetenv(key string) {
CmdNameRedoAffects,
CmdNameRedoAlways,
CmdNameRedoCleanup,
+ CmdNameRedoDepFix,
CmdNameRedoDot,
CmdNameRedoIfchange,
CmdNameRedoIfcreate,
fmt.Println(os.Args[0], "<-", cmdName)
if err := os.Symlink(os.Args[0], cmdName); err != nil {
rc = 1
- log.Println(err)
+ log.Print(err)
}
}
os.Exit(rc)
}
log.SetFlags(log.Lshortfile)
+ UmaskCur = syscall.Umask(0)
+ syscall.Umask(UmaskCur)
+
var err error
Cwd, err = os.Getwd()
if err != nil {
- log.Fatalln(err)
+ log.Fatal(err)
}
TopDir = os.Getenv(EnvTopDir)
}
NoColor = os.Getenv(EnvNoColor) != ""
NoSync = os.Getenv(EnvNoSync) == "1"
+ StopIfMod = os.Getenv(EnvStopIfMod) == "1"
switch s := os.Getenv(EnvInodeTrust); s {
case "none":
InodeTrust = InodeTrustNone
tracef(CDebug, "inode-trust: %s", InodeTrust)
// Those are internal envs
- FdOODTgts, err = ioutil.TempFile("", "ood-tgts")
+ FdOODTgts, err = os.CreateTemp("", "ood-tgts")
if err != nil {
- log.Fatalln(err)
+ log.Fatal(err)
}
if err = os.Remove(FdOODTgts.Name()); err != nil {
- log.Fatalln(err)
+ log.Fatal(err)
}
- FdOODTgtsLock, err = ioutil.TempFile("", "ood-tgts.lock")
+ FdOODTgtsLock, err = os.CreateTemp("", "ood-tgts.lock")
if err != nil {
- log.Fatalln(err)
+ log.Fatal(err)
}
if err = os.Remove(FdOODTgtsLock.Name()); err != nil {
- log.Fatalln(err)
+ log.Fatal(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 {
- log.Fatalln(err)
+ flock := unix.Flock_t{
+ Type: unix.F_WRLCK,
+ Whence: io.SeekStart,
+ }
+ if err = unix.FcntlFlock(fdLock.Fd(), unix.F_SETLKW, &flock); err != nil {
+ log.Fatal(err)
}
if _, err = fd.Seek(0, io.SeekStart); err != nil {
- log.Fatalln(err)
+ log.Fatal(err)
}
- tgtsRaw, err := ioutil.ReadAll(bufio.NewReader(fd))
+ tgtsRaw, err := io.ReadAll(bufio.NewReader(fd))
if err != nil {
- log.Fatalln(err)
+ log.Fatal(err)
}
- if err = unix.Flock(int(fdLock.Fd()), unix.LOCK_UN); err != nil {
- log.Fatalln(err)
+ flock.Type = unix.F_UNLCK
+ if err = unix.FcntlFlock(fdLock.Fd(), unix.F_SETLK, &flock); err != nil {
+ log.Fatal(err)
}
OODTgts = map[string]struct{}{}
for _, tgtRaw := range bytes.Split(tgtsRaw, []byte{0}) {
IsTopRedo = true
raw := new([16]byte)
if _, err = io.ReadFull(rand.Reader, raw[:]); err != nil {
- log.Fatalln(err)
+ log.Fatal(err)
}
raw[6] = (raw[6] & 0x0F) | uint8(4<<4) // version 4
BuildUUID = fmt.Sprintf(
}
}
- if cmdName == CmdNameRedo || cmdName == CmdNameRedoIfchange {
+ if cmdName == CmdNameRedo {
statusInit()
}
}
}
case CmdNameRedoIfchange:
- ok, err = ifchange(tgts, false, traced)
+ ok, err = ifchange(tgts, *flagForcedIfchange, traced)
if err == nil {
err = depsWrite(fdDep, tgts)
}
}
for _, tgt := range tgts {
tgtRel, err := filepath.Rel(
- filepath.Join(Cwd, DirPrefix),
- filepath.Join(Cwd, tgt),
+ path.Join(Cwd, DirPrefix),
+ path.Join(Cwd, tgt),
)
if err != nil {
break
err = stamp(fdDep, os.Stdin)
case CmdNameRedoLog:
if len(tgts) != 1 {
- log.Fatalln("single target expected")
+ log.Fatal("single target expected")
}
d, t := cwdAndTgt(tgts[0])
err = showBuildLog(d, t, nil, 0)
case CmdNameRedoWhichdo:
if len(tgts) != 1 {
- log.Fatalln("single target expected")
+ log.Fatal("single target expected")
}
var fdTmp *os.File
- fdTmp, err = ioutil.TempFile("", "whichdo")
+ fdTmp, err = os.CreateTemp("", "whichdo")
if err != nil {
break
}
}
case CmdNameRedoAffects:
if tgtsWasEmpty {
- log.Fatalln("no targets specified")
+ log.Fatal("no targets specified")
}
var tgtsKnown []string
tgtsKnown, err = targetsWalker([]string{Cwd})
}
deps := map[string]map[string]struct{}{}
for _, tgt := range tgtsKnown {
- collectDeps(Cwd, tgt, 0, deps, true)
+ collectDeps(Cwd, tgt, 0, deps, true, map[string]struct{}{})
}
seen := map[string]struct{}{}
for _, tgt := range tgts {
for _, src := range srcs {
fmt.Println(src)
}
+ case CmdNameRedoDepFix:
+ err = depFix(Cwd)
+ case CmdNameRedoInode:
+ var inode *Inode
+ for _, tgt := range tgts {
+ inode, err = inodeFromFileByPath(tgt)
+ if err != nil {
+ break
+ }
+ err = recfileWrite(os.Stdout, append(
+ []recfile.Field{{Name: "Target", Value: tgt}},
+ inode.RecfileFields()...)...)
+ if err != nil {
+ break
+ }
+ }
default:
log.Fatalln("unknown command", cmdName)
}
if err != nil {
- log.Println(err)
+ log.Print(err)
}
rc := 0
if !ok || err != nil {