diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2017-11-15 16:19:23 -0500 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2017-11-15 16:19:23 -0500 |
commit | 29c005aded55168631029f9b129ff812ff96f802 (patch) | |
tree | 466eed0750d8976110e62e947c6ef6102dd450bb | |
parent | 902bb1cc2a0a8644e160f303be1a2e0ad354bfd5 (diff) |
more
-rw-r--r-- | commands.go | 32 | ||||
-rw-r--r-- | f.txt | 13 | ||||
-rw-r--r-- | fileactions.go | 66 | ||||
-rw-r--r-- | filter.go | 103 | ||||
-rw-r--r-- | git-fast-import.go | 127 | ||||
-rw-r--r-- | io.go | 16 | ||||
-rw-r--r-- | read.go | 18 | ||||
-rw-r--r-- | types.go | 2 | ||||
-rw-r--r-- | util.go | 28 |
9 files changed, 127 insertions, 278 deletions
diff --git a/commands.go b/commands.go index 6c5a0c7..a1f7f51 100644 --- a/commands.go +++ b/commands.go @@ -4,32 +4,8 @@ import ( "strconv" ) -type ezfiw struct { - fiw *FIWriter - err error -} - -func (e *ezfiw) WriteLine(a ...interface{}) { - if e.err == nil { - e.err = e.fiw.WriteLine(a...) - } -} - -func (e *ezfiw) WriteData(data []byte) { - if e.err == nil { - e.err = e.fiw.WriteData(data) - } -} - -func (e *ezfiw) WriteMark(idnum int) { - if e.err == nil { - e.err = e.fiw.WriteLine("mark", ":"+strconv.Itoa(idnum)) - } -} - type Cmd interface { fiWriteCmd(*FIWriter) error - fiReadCmd(*FIReader) error } type CmdCommit struct { @@ -53,7 +29,7 @@ func (c *CmdCommit) fiWriteCmd(fiw *FIWriter) error { ez.WriteLine("author", *c.Author) } ez.WriteLine("committer", c.Committer) - ez.WriteData(c.Data) + ez.WriteData(c.Msg) if len(c.Parents) > 0 { ez.WriteLine("from", c.Parents[0]) if len(c.Parents) > 1 { @@ -68,7 +44,7 @@ func (c *CmdCommit) fiWriteCmd(fiw *FIWriter) error { } for _, action := range c.Tree { - err := action.fiWriteFA(fi) + err := action.fiWriteFA(fiw) if err != nil { return err } @@ -120,7 +96,7 @@ func (c *CmdBlob) fiWriteCmd(fiw *FIWriter) error { ez := &ezfiw{fiw: fiw} ez.WriteLine("blob") - if mark > 0 { + if c.Mark > 0 { ez.WriteMark(c.Mark) } ez.WriteData(c.Data) @@ -146,7 +122,7 @@ type CmdGetMark struct { Mark int } -func (c *CmdGetmark) fiWriteCmd(fiw *FIWriter) error { +func (c *CmdGetMark) fiWriteCmd(fiw *FIWriter) error { return fiw.WriteLine("get-mark", ":"+strconv.Itoa(c.Mark)) } @@ -1,13 +0,0 @@ -commit -tag -reset -blob -checkpoint -progress -feature -option -done -# -get-mark -cat-blob -ls diff --git a/fileactions.go b/fileactions.go index b45f776..2d81177 100644 --- a/fileactions.go +++ b/fileactions.go @@ -1,43 +1,47 @@ +package libfastimport + type FileAction interface { - fiWrite(fi *FastImport) error + fiWriteFA(*FIWriter) error } type FileModify struct { - Mode FileMode - Path string + Mode Mode + Path Path DataRef string } -func (o FileModify) fiWrite(fi *FastImport) error { - return fi.printf(w, "M %06o %s %s\n", o.Mode, o.DataRef, pathEscape(o.Path)) +func (o FileModify) fiWriteFA(fiw *FIWriter) error { + return fiw.WriteLine("M", o.Mode, o.DataRef, o.Path) } type FileModifyInline struct { - Mode FileMode - Path string + Mode Mode + Path Path Data []byte } -func (o FileModifyInline) fiWrite(fi *FastImport) error { - fi.printf("M %06o inline %s\n", o.Mode, pathEscape(o.Path)) - return fi.data(o.Data) +func (o FileModifyInline) fiWriteFA(fiw *FIWriter) error { + ez := &ezfiw{fiw: fiw} + ez.WriteLine("M", o.Mode, "inline", o.Path) + ez.WriteData(o.Data) + return ez.err } type FileDelete struct { - Path string + Path Path } -func (o FileDelete) fiWrite(fi *FastImport) error { - return fi.printf("D %s\n", pathEscape(o.Path)) +func (o FileDelete) fiWriteFA(fiw *FIWriter) error { + return fiw.WriteLine("D", o.Path) } type FileCopy struct { - Src string - Dst string + Src Path + Dst Path } -func (o FileCopy) fiWrite(fi *FastImport) error { - return fi.printf("C %s %s\n", pathEscape(o.Src), pathEscape(o.Dst)) +func (o FileCopy) fiWriteFA(fiw *FIWriter) error { + return fiw.WriteLine("C", o.Src, o.Dst) } type FileRename struct { @@ -45,14 +49,14 @@ type FileRename struct { Dst string } -func (o FileRename) fiWrite(fi *FastImport) error { - return fi.printf("R %s %s\n", pathEscape(o.Src), pathEscape(o.Dst)) +func (o FileRename) fiWriteFA(fiw *FIWriter) error { + return fiw.WriteLine("R", o.Src, o.Dst) } type FileDeleteAll struct{} -func (o FileDeleteAll) fiWrite(fi *FastImport) error { - return fi.printf("deleteall\n") +func (o FileDeleteAll) fiWriteFA(fiw *FIWriter) error { + return fiw.WriteLine("deleteall") } type NoteModify struct { @@ -60,8 +64,8 @@ type NoteModify struct { DataRef string } -func (o NoteModify) fiWrite(fi *FastImport) error { - return fi.printf("N %s %s\n", o.DataRef, o.CommitIsh) +func (o NoteModify) fiWriteFA(fiw *FIWriter) error { + return fiw.WriteLine("N", o.DataRef, o.CommitIsh) } type NoteModifyInline struct { @@ -69,8 +73,18 @@ type NoteModifyInline struct { Data []byte } -func (o NoteModify) fiWrite(fi *FastImport) error { - fi.printf("N inline %s\n", o.CommitIsh) - return fi.data(o.Data) +func (o NoteModifyInline) fiWriteFA(fiw *FIWriter) error { + ez := &ezfiw{fiw: fiw} + ez.WriteLine("N", "inline", o.CommitIsh) + ez.WriteData(o.Data) + return ez.err } +// See CmdLs for using ls outside of a commit +type FileLs struct { + Path Path +} + +func (o FileLs) fiWriteFA(fiw *FIWriter) error { + return fiw.WriteLine("ls", o.Path) +} diff --git a/filter.go b/filter.go deleted file mode 100644 index 0c09963..0000000 --- a/filter.go +++ /dev/null @@ -1,103 +0,0 @@ -package main - -import ( - "os" - "os/exec" - "bytes" -) - -var prog [string]string - -func init() { - var err error - for _, p := range []string{"git", "makepkg"} { - prog[p], err = exec.LookPath("git") - if err != nil { - panic(err) - } - } -} - -func pipeline(cmds ...*exec.Cmd) err error { - for i, cmd := range cmds[:len(cmds)-1] { - cmds[i+1].Stdin, err = cmd.StdoutPipe() - if err != nil { - return - } - } - - stderr := make([]bytes.Buffer, len(cmds)) - for i, cmd := range cmds { - cmd.Stderr = &stderr[i] - if err = cmd.Start(); err != nil { - break - } - } - - for i, cmd := range cmds { - if cmd.Process == nil { - continue - } - if _err := cmd.Wait(); _err != nil { - if ee, ok := _err.(*exec.ExitError); ok { - ee.Stderr = stderr[i].Bytes() - } - if err != nil { - err = _err - } - } - } - return -} - -func pkgbuild2srcinfo(pkgbuildId string) (string, error) { - cachefilename := "filter/pkgbuild2srcinfo/"+pkgbuildId - for { - b, err := ioutil.ReadFile(cachefilename) - if err == nil && len(bytes.TrimSpace(b)) == 40 { - return bytes.TrimSpace(b).String(), nil - } - - file, err := os.OpenFile("filter/tmp/PKGBUILD", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - return "", err - } - err = pipeline( - &exec.Cmd{ - Path: prog["git"], Args: ["git", "cat-file", "blob", pkgbuildId], - Stdout: file, - }) - file.Close() - if err != nil { - return "", err - } - - - file, err = os.OpenFile(cachefilename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) - err = pipeline( - &exec.Cmd{ - Path: prog["makepkg"], Args: ["makepkg", "--printsrcinfo"], - Dir: "filter/tmp" - }, - &exec.Cmd{ - Path: prog["git"], Args: ["git", "hash-object", "-t", "blob", "-w", "--stdin", "--no-filters"], - Stdout: &buf, - }) - file.Close() - if err != nil { - return "", err - } - } -} - - - -func filter(fromPfix string, toPfix string) { - exec.Cmd{ - Path: prog["git"], Args: ["git", "fast-export", - "--use-done-feature", - "--no-data", - "--", fromPfix + "/master"], - } - -} diff --git a/git-fast-import.go b/git-fast-import.go index d9c7795..ed5cb14 100644 --- a/git-fast-import.go +++ b/git-fast-import.go @@ -1,118 +1,69 @@ package libfastimport import ( - "time" + "fmt" + "bytes" + "strconv" ) -type FastImport struct { - w *FIWriter - r *CatBlobReader - err error -} - -func (fi *FastImport) GetMark(mark int) (string, error) { - if fi.printf("get-mark :%d\n", mark) != nil { - return "", fi.ioErr - } - var dat [41]byte - var n int - _, fi.ioErr = io.ReadFull(fi.r, dat[:]) - if fi.ioErr != nil { - return "", fi.ioErr +func CatBlobParseGetMark(dat []byte) (string, error) { + if len(dat) != 41 { + return "", fmt.Errorf("get-mark: short <sha1>\\n: %q", string(dat)) } if dat[40] != '\n' { - fi.ioErr = fmt.Errorf("get-mark: malformed <sha1>\\n: %q", string(dat)) - return "", fi.ioErr + return "", fmt.Errorf("get-mark: malformed <sha1>\\n: %q", string(dat)) } for _, b := range dat[:40] { if !(('0' <= b && b <= '9') || ('a' <= b && b <= 'f')) { - fi.ioErr = fmt.Errorf("get-mark: malformed <sha1>: %q", string(dat[:40])) - return "", fi.ioErr + return "", fmt.Errorf("get-mark: malformed <sha1>: %q", string(dat[:40])) } } - return string(dat[:40]) + return string(dat[:40]), nil } -func (fi *FastImport) CatBlob(dataref string) (sha1 string, data []byte, err error) { - if fi.println("cat-blob %s\n", dataref) != nil { - return "", nil, fi.ioErr - } - // <sha1> SP 'blob' SP <size> LF +func CatBlobParseCatBlob(full []byte) (sha1 string, data []byte, err error) { + // The format is: // - // That comes out to be 47+len(itoa(size)). Assuming that - // size is at most a 64-bit integer (a safe assumption), then - // its limit is 20 digits. - var head [67]byte - i := 0 - for { - _, fi.ioErr = io.ReadFull(fi.r, head[i:i+1]) - if fi.ioErr != nil { - return "", nil, fi.ioErr - } - if head[i] == '\n' { - break - } - i++ - if i == len(head) { - fi.ioErr = fmt.Errorf("cat-blob: overly-long header line: %q", string(head)) - return "", nil, fi.ioErr - } + // <sha1> SP 'blob' SP <size> LF + // <data> LF + + lf := bytes.IndexByte(full, '\n') + if lf < 0 || lf == len(full)-1 { + return "", nil, fmt.Errorf("cat-blob: malformed header: %q", string(full)) } - i-- - if head[i] != '\n' { - panic("wut") + head := full[:lf] + data = full[lf+1:len(full)-1] + + if len(head) < 40+6+1 { + return "", nil, fmt.Errorf("cat-blob: malformed header: %q", string(head)) } - for _, b := range head[:40] { + + sha1 = string(head[:40]) + for _, b := range sha1 { if !(('0' <= b && b <= '9') || ('a' <= b && b <= 'f')) { - fi.ioErr = fmt.Errorf("cat-blob: malformed <sha1>: %q", string(head[:40])) - return "", nil, fi.ioErr + return "", nil, fmt.Errorf("cat-blob: malformed <sha1>: %q", sha1) } } + if string(head[40:46]) != " blob " { - fi.ioErr = fmt.Errorf("cat-blob: malformed header: %q", string(head[:i])) - return "", nil, fi.ioErr + return "", nil, fmt.Errorf("cat-blob: malformed header: %q", head) } - size, err := strconv.Atoi(string(head[46:i])) + + size, err := strconv.Atoi(string(head[46:])) if err != nil { - fi.ioErr = fmt.Errorf("cat-blob: malformed blob size: %v", err) - return "", nil, fi.ioErr - } - dat := make([]byte, size+1) - _, fi.ioErr = io.ReadFull(fi.r, dat) - if dat[size] != '\n' { - fi.ioErr = fmt.Errorf("cat-blob: expected newline after data") - return "", nil, fi.ioErr + return "", nil, fmt.Errorf("cat-blob: malformed blob size: %v", err) } - return string(head[:40]), dat[:size], nil -} -func (fi *FastImport) Ls(dataref string, path string) error { - if dataref == "" { - fi.printf("ls %s\n", quotePath(path)) - } else { - fi.printf("ls %s %s\n", dataref, quotePath(path)) - } - if fi.ioErr != nil { - return fi.ioErr + if size != len(data) { + return "", nil, fmt.Errorf("cat-blob: size header (%d) didn't match delivered size (%d)", size, len(data)) } - k -} -func (fi *FastImport) Feature() error -func (fi *FastImport) Option() error -func (fi *FastImport) Done() error { - fi.printf("done\n") - if fi.ioErr == nil { - fi.ioErr = w.Close() - } - return fi.ioErr + return sha1, data, err } -func init() { - x := exec.Cmd{ - Path: prog["git"], - Args: {"git", "fast-import", - "--done", - "--cat-blob-fd=" + strconv.Itoa(TODO)}, - } +func CatBlobParseLs(dataref string, path string) error { + // <mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF + // or + // 'missing' SP <path> LF + return nil // TODO } @@ -1,6 +1,7 @@ package libfastimport import ( + "fmt" "bufio" "bytes" "io" @@ -39,7 +40,7 @@ retry: for !bytes.HasSuffix(line, suffix) { _line, err = fir.r.ReadSlice('\n') - line == append(line, _line) + line = append(line, _line...) if err != nil { return } @@ -53,7 +54,8 @@ retry: } _line := make([]byte, size+len(line)) copy(_line, line) - n, err := io.ReadFull(fir.r, _line[len(line):]) + var n int + n, err = io.ReadFull(fir.r, _line[len(line):]) line = _line[:n+len(line)] } } @@ -70,12 +72,12 @@ func NewFIWriter(w io.Writer) *FIWriter { } } -func (fiw *FIReader) WriteLine(a ...interface{}) error { +func (fiw *FIWriter) WriteLine(a ...interface{}) error { _, err := fmt.Fprintln(fiw.w, a...) return err } -func (fiw *FIReader) WriteData(data []byte) error { +func (fiw *FIWriter) WriteData(data []byte) error { err := fiw.WriteLine("data", len(data)) if err != nil { return err @@ -96,7 +98,7 @@ func NewCatBlobReader(r io.Reader) *CatBlobReader { func (cbr *CatBlobReader) ReadSlice() (line []byte, err error) { retry: - line, err = fir.r.ReadSlice('\n') + line, err = cbr.r.ReadSlice('\n') if err != nil { return } @@ -124,9 +126,9 @@ retry: if err != nil { return } - _line = make([]byte, len(line)+size+1) + _line := make([]byte, len(line)+size+1) copy(_line, line) - n, err := io.ReadFull(fir.r, _line[len(line):]) + n, err := io.ReadFull(cbr.r, _line[len(line):]) line = _line[:n+len(line)] return } @@ -23,33 +23,26 @@ func (p *Parser) GetCmd() (Cmd, error) { return nil, err } } - return p.cmd, nil + return <-p.cmd, nil } func (p *Parser) putSlice(slice []byte) error { -} - -func utSlice(fir *FIReader) (Cmd, error) { - slice, err := fir.PeekSlice() - if err != nil { - return nil, err - } if len(slice) < 1 { - return nil, UnsupportedCommand(slice) + return UnsupportedCommand(slice) } switch slice[0] { case '#': // comment case 'b': // blob case 'c': if len(slice) < 2 { - return nil, UnsupportedCommand(slice) + return UnsupportedCommand(slice) } switch slice[1] { case 'o': // commit case 'h': // checkpoint case 'a': // cat-blob default: - return nil, UnsupportedCommand(slice) + return UnsupportedCommand(slice) } case 'd': // done case 'f': // feature @@ -60,6 +53,7 @@ func utSlice(fir *FIReader) (Cmd, error) { case 'r': // reset case 't': // tag default: - return nil, UnsupportedCommand(slice) + return UnsupportedCommand(slice) } + return nil // TODO } @@ -43,7 +43,7 @@ func (m Mode) String() string { } func PathEscape(path string) string { - if strings.HasPrefix(path, "\"") || strings.ContainsRune("\n") { + if strings.HasPrefix(path, "\"") || strings.ContainsRune(path, '\n') { return "\"" + strings.Replace(strings.Replace(strings.Replace(path, "\\", "\\\\", -1), "\"", "\\\"", -1), "\n", "\\n", -1) + "\"" } else { return path @@ -0,0 +1,28 @@ +package libfastimport + +import ( + "strconv" +) + +type ezfiw struct { + fiw *FIWriter + err error +} + +func (e *ezfiw) WriteLine(a ...interface{}) { + if e.err == nil { + e.err = e.fiw.WriteLine(a...) + } +} + +func (e *ezfiw) WriteData(data []byte) { + if e.err == nil { + e.err = e.fiw.WriteData(data) + } +} + +func (e *ezfiw) WriteMark(idnum int) { + if e.err == nil { + e.err = e.fiw.WriteLine("mark", ":"+strconv.Itoa(idnum)) + } +} |