X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=main.go;h=c579a0f6ec935414ff18815fa3eaf0aea62ebcb1;hb=6dce71355599d4caf8267f6f02520037480f7ba3;hp=018aaf177474a914fd77536712fcc83438312d80;hpb=e1afa1a3b0f7e4e06f636f584a47bb8cfc885e7c;p=goredo.git diff --git a/main.go b/main.go index 018aaf1..c579a0f 100644 --- a/main.go +++ b/main.go @@ -20,8 +20,7 @@ package main import ( "bufio" "bytes" - "crypto/rand" - "errors" + "encoding/hex" "flag" "fmt" "io" @@ -34,6 +33,7 @@ import ( "strconv" "syscall" + "github.com/google/uuid" "go.cypherpunks.ru/recfile" "golang.org/x/sys/unix" ) @@ -44,6 +44,7 @@ const ( CmdNameRedoAffects = "redo-affects" CmdNameRedoAlways = "redo-always" CmdNameRedoCleanup = "redo-cleanup" + CmdNameRedoDep2Rec = "redo-dep2rec" CmdNameRedoDepFix = "redo-depfix" CmdNameRedoDot = "redo-dot" CmdNameRedoIfchange = "redo-ifchange" @@ -59,7 +60,7 @@ const ( var ( Cwd string - BuildUUID string + BuildUUID uuid.UUID IsTopRedo bool // is it the top redo instance UmaskCur int ) @@ -113,6 +114,7 @@ func main() { CmdNameRedoAffects, CmdNameRedoAlways, CmdNameRedoCleanup, + CmdNameRedoDep2Rec, CmdNameRedoDepFix, CmdNameRedoDot, CmdNameRedoIfchange, @@ -281,23 +283,19 @@ func main() { 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 { @@ -323,7 +321,6 @@ func main() { tracef(CDebug, "[%s] run: %s %s cwd:%s dirprefix:%s", BuildUUID, cmdName, tgts, Cwd, DirPrefix) -CmdSwitch: switch cmdName { case CmdNameRedo: for _, tgt := range tgts { @@ -341,20 +338,22 @@ CmdSwitch: 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 } @@ -365,7 +364,12 @@ CmdSwitch: 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") @@ -375,52 +379,14 @@ CmdSwitch: 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 - } - err = ErrLine(os.Remove(fdTmp.Name())) - if err != nil { - break - } - tgt := tgts[0] - var doFile string - var upLevels int - 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)) @@ -453,7 +419,7 @@ CmdSwitch: } 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 { @@ -527,9 +493,11 @@ CmdSwitch: 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 { @@ -544,6 +512,66 @@ CmdSwitch: 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) }