import (
"bufio"
"bytes"
- "crypto/rand"
- "errors"
+ "encoding/hex"
"flag"
"fmt"
"io"
"strconv"
"syscall"
+ "github.com/google/uuid"
"go.cypherpunks.ru/recfile"
"golang.org/x/sys/unix"
)
CmdNameRedoAffects = "redo-affects"
CmdNameRedoAlways = "redo-always"
CmdNameRedoCleanup = "redo-cleanup"
+ CmdNameRedoDep2Rec = "redo-dep2rec"
CmdNameRedoDepFix = "redo-depfix"
CmdNameRedoDot = "redo-dot"
CmdNameRedoIfchange = "redo-ifchange"
var (
Cwd string
- BuildUUID string
+ BuildUUID uuid.UUID
IsTopRedo bool // is it the top redo instance
UmaskCur int
)
CmdNameRedoAffects,
CmdNameRedoAlways,
CmdNameRedoCleanup,
+ CmdNameRedoDep2Rec,
CmdNameRedoDepFix,
CmdNameRedoDot,
CmdNameRedoIfchange,
for _, arg := range flag.Args() {
tgts = append(tgts, NewTgt(arg))
}
- BuildUUID = os.Getenv(EnvBuildUUID)
tgtsWasEmpty := len(tgts) == 0
- if BuildUUID == "" {
+ if BuildUUIDStr := os.Getenv(EnvBuildUUID); BuildUUIDStr == "" {
IsTopRedo = true
- raw := new([16]byte)
- if _, err = io.ReadFull(rand.Reader, raw[:]); err != nil {
- log.Fatal(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:],
- )
+ BuildUUID = uuid.New()
if tgtsWasEmpty {
tgts = append(tgts, NewTgt("all"))
}
tracef(CDebug, "inode-trust: %s", InodeTrust)
+ } else {
+ BuildUUID, err = uuid.Parse(BuildUUIDStr)
+ if err != nil {
+ log.Fatal(err)
+ }
}
if cmdName == CmdNameRedo {
ok := true
err = nil
- tracef(
- CDebug, "[%s] run: %s %s cwd:%s dirprefix:%s",
- BuildUUID, cmdName, tgts, Cwd, DirPrefix,
- )
+ tracef(CDebug, "[%s] run: %s %s cwd:%s dirprefix:%s",
+ BuildUUID, cmdName, tgts, Cwd, DirPrefix)
-CmdSwitch:
switch cmdName {
case CmdNameRedo:
for _, tgt := range tgts {
if fdDep == nil {
log.Fatalln("no", EnvDepFd)
}
+ fdDepW := bufio.NewWriter(fdDep)
for _, tgt := range tgts {
- err = ifcreate(fdDep, tgt.RelTo(path.Join(Cwd, DirPrefix)))
+ err = ifcreate(fdDepW, fdDep.Name(), tgt.RelTo(path.Join(Cwd, DirPrefix)))
if err != nil {
break
}
}
+ err = fdDepW.Flush()
case CmdNameRedoAlways:
if fdDep == nil {
log.Fatalln("no", EnvDepFd)
}
- err = always(fdDep)
+ err = always(fdDep, fdDep.Name())
case CmdNameRedoCleanup:
for _, what := range tgts {
- err = cleanupWalker(Cwd, what.t)
+ err = cleanupWalker(Cwd, path.Base(what.a))
if err != nil {
break
}
if fdDep == nil {
log.Fatalln("no", EnvDepFd)
}
- err = stamp(fdDep, os.Stdin)
+ var hsh Hash
+ hsh, err = fileHash(os.Stdin)
+ if err != nil {
+ break
+ }
+ err = stamp(fdDep, fdDep.Name(), hsh)
case CmdNameRedoLog:
if len(tgts) != 1 {
log.Fatal("single target expected")
if len(tgts) != 1 {
log.Fatal("single target expected")
}
- var fdTmp *os.File
- fdTmp, err = os.CreateTemp("", "whichdo")
+ var dos []string
+ dos, err = whichdo(tgts[0])
if err != nil {
- err = ErrLine(err)
- break
- }
- if err = os.Remove(fdTmp.Name()); err != nil {
- err = ErrLine(err)
- break
- }
- tgt := tgts[0]
- doFile, upLevels, err := findDo(fdTmp, tgt.h, tgt.t)
- if err != nil {
- err = ErrLine(err)
- break
- }
- _, err = fdTmp.Seek(0, io.SeekStart)
- if err != nil {
- err = ErrLine(err)
break
}
- r := recfile.NewReader(fdTmp)
- for {
- m, err := r.NextMap()
- if err != nil {
- if errors.Is(err, io.EOF) {
- break
- }
- err = ErrLine(err)
- break CmdSwitch
- }
- fmt.Println(cwdMustRel(tgt.h, m["Target"]))
- }
- if doFile == "" {
- ok = false
- } else {
- p := make([]string, 0, upLevels+2)
- p = append(p, tgt.h)
- for i := 0; i < upLevels; i++ {
- p = append(p, "..")
- }
- p = append(p, doFile)
- rel := mustRel(Cwd, path.Join(p...))
- fmt.Println(rel)
+ sort.Strings(dos)
+ for _, do := range dos {
+ fmt.Println(do)
}
case CmdNameRedoTargets:
raws := make([]string, 0, len(tgts))
for _, tgt := range tgts {
- raws = append(raws, tgt.String())
+ raws = append(raws, tgt.rel)
}
if tgtsWasEmpty {
raws = []string{Cwd}
}
deps := make(map[string]map[string]*Tgt)
for _, tgt := range tgtsKnown {
- collectDeps(NewTgt(tgt), 0, deps, true, make(map[string]struct{}))
+ collectDeps(NewTgt(tgt), 0, deps, true)
}
seen := make(map[string]*Tgt)
for _, tgt := range tgts {
- collectWholeDeps(deps[tgt.a], deps, seen)
+ collectWholeDeps(deps[tgt.rel], deps, seen)
}
res = make([]string, 0, len(seen))
for _, dep := range seen {
- res = append(res, dep.String())
+ res = append(res, dep.rel)
}
}
sort.Strings(res)
case CmdNameRedoOOD:
raws := make([]string, 0, len(tgts))
for _, tgt := range tgts {
- raws = append(raws, tgt.String())
+ raws = append(raws, tgt.rel)
}
if tgtsWasEmpty {
raws, err = targetsWalker([]string{Cwd})
{
raws := make([]string, 0, len(tgts))
for _, tgt := range tgts {
- raws = append(raws, tgt.String())
+ raws = append(raws, tgt.rel)
}
if tgtsWasEmpty {
raws, err = targetsWalker([]string{Cwd})
}
res := make([]string, 0, len(srcs))
for _, tgt := range srcs {
- res = append(res, tgt.String())
+ res = append(res, tgt.rel)
}
srcs = nil
sort.Strings(res)
fmt.Println(src)
}
case CmdNameRedoDepFix:
+ IfchangeCache = nil
+ DepFixHashCache = make(map[string]Hash)
err = depFix(Cwd)
case CmdNameRedoInode:
- var inode *Inode
+ var inode Inode
for _, tgt := range tgts {
inode, err = inodeFromFileByPath(tgt.a)
if err != nil {
break
}
}
+ case CmdNameRedoDep2Rec:
+ var data []byte
+ data, err = os.ReadFile(tgts[0].a)
+ if err != nil {
+ break
+ }
+ var build uuid.UUID
+ build, data, err = depHeadParse(data)
+ if err != nil {
+ break
+ }
+ w := bufio.NewWriter(os.Stdout)
+ err = recfileWrite(w, []recfile.Field{
+ {Name: "Build", Value: build.String()},
+ }...)
+ if err != nil {
+ break
+ }
+ var typ byte
+ var chunk []byte
+ for len(data) > 0 {
+ typ, chunk, data, _ = chunkRead(data)
+ switch typ {
+ case DepTypeAlways:
+ err = recfileWrite(w, []recfile.Field{
+ {Name: "Type", Value: "always"},
+ }...)
+ case DepTypeStamp:
+ err = recfileWrite(w, []recfile.Field{
+ {Name: "Type", Value: "stamp"},
+ {Name: "Hash", Value: hex.EncodeToString(chunk)},
+ }...)
+ case DepTypeIfcreate:
+ err = recfileWrite(w, []recfile.Field{
+ {Name: "Type", Value: "ifcreate"},
+ {Name: "Target", Value: string(chunk)},
+ }...)
+ case DepTypeIfchange:
+ name := string(chunk[InodeLen+HashLen:])
+ meta := string(chunk[:InodeLen+HashLen])
+ fields := []recfile.Field{
+ {Name: "Type", Value: "ifchange"},
+ {Name: "Target", Value: name},
+ }
+ fields = append(fields, recfile.Field{
+ Name: "Hash", Value: Hash(meta[InodeLen:]).String(),
+ })
+ fields = append(fields, Inode(meta[:InodeLen]).RecfileFields()...)
+ err = recfileWrite(w, fields...)
+ case DepTypeIfchangeDummy:
+ err = recfileWrite(w, []recfile.Field{
+ {Name: "Type", Value: "ifchange"},
+ {Name: "Target", Value: string(chunk)},
+ }...)
+ }
+ if err != nil {
+ break
+ }
+ }
+ err = w.Flush()
default:
log.Fatalln("unknown command", cmdName)
}