]> Cypherpunks.ru repositories - goredo.git/blobdiff - main.go
Binary format and many optimisations
[goredo.git] / main.go
diff --git a/main.go b/main.go
index 018aaf177474a914fd77536712fcc83438312d80..c579a0f6ec935414ff18815fa3eaf0aea62ebcb1 100644 (file)
--- 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)
        }