From efc7a5ebc9e10983571c080017100a8b39eee1d0 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 15 Nov 2017 21:39:40 -0500 Subject: more --- commands.go | 38 +++++++------- ezfiw.go | 4 +- fileactions.go | 40 +++++++------- frontend.go | 68 ++++++++++++++++++++++++ io.go | 152 ----------------------------------------------------- parse_catblob.go | 97 ++++++++++++++++++++++++++++++++++ read_catblob.go | 69 ------------------------ read_fastimport.go | 28 +++++----- textproto/io.go | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++ textproto/types.go | 65 +++++++++++++++++++++++ types.go | 65 ----------------------- 11 files changed, 437 insertions(+), 335 deletions(-) create mode 100644 frontend.go delete mode 100644 io.go create mode 100644 parse_catblob.go delete mode 100644 read_catblob.go create mode 100644 textproto/io.go create mode 100644 textproto/types.go delete mode 100644 types.go diff --git a/commands.go b/commands.go index a1f7f51..d017f7f 100644 --- a/commands.go +++ b/commands.go @@ -2,23 +2,25 @@ package libfastimport import ( "strconv" + + "git.lukeshu.com/go/libfastimport/textproto" ) type Cmd interface { - fiWriteCmd(*FIWriter) error + fiWriteCmd(*textproto.FIWriter) error } type CmdCommit struct { Ref string Mark int // optional; < 1 for non-use - Author *UserTime - Committer UserTime + Author *textproto.UserTime + Committer textproto.UserTime Msg []byte Parents []string Tree []FileAction } -func (c *CmdCommit) fiWriteCmd(fiw *FIWriter) error { +func (c CmdCommit) fiWriteCmd(fiw *textproto.FIWriter) error { ez := &ezfiw{fiw: fiw} ez.WriteLine("commit", c.Ref) @@ -56,11 +58,11 @@ func (c *CmdCommit) fiWriteCmd(fiw *FIWriter) error { type CmdTag struct { RefName string CommitIsh string - Tagger UserTime + Tagger textproto.UserTime Data []byte } -func (c *CmdTag) fiWriteCmd(fiw *FIWriter) error { +func (c CmdTag) fiWriteCmd(fiw *textproto.FIWriter) error { ez := &ezfiw{fiw: fiw} ez.WriteLine("tag", c.RefName) @@ -76,7 +78,7 @@ type CmdReset struct { CommitIsh string // optional } -func (c *CmdReset) fiWriteCmd(fiw *FIWriter) error { +func (c CmdReset) fiWriteCmd(fiw *textproto.FIWriter) error { ez := &ezfiw{fiw: fiw} ez.WriteLine("reset", c.RefName) @@ -92,7 +94,7 @@ type CmdBlob struct { Data []byte } -func (c *CmdBlob) fiWriteCmd(fiw *FIWriter) error { +func (c CmdBlob) fiWriteCmd(fiw *textproto.FIWriter) error { ez := &ezfiw{fiw: fiw} ez.WriteLine("blob") @@ -106,7 +108,7 @@ func (c *CmdBlob) fiWriteCmd(fiw *FIWriter) error { type CmdCheckpoint struct{} -func (c *CmdCheckpoint) fiWriteCmd(fiw *FIWriter) error { +func (c CmdCheckpoint) fiWriteCmd(fiw *textproto.FIWriter) error { return fiw.WriteLine("checkpoint") } @@ -114,7 +116,7 @@ type CmdProgress struct { Str string } -func (c *CmdProgress) fiWriteCmd(fiw *FIWriter) error { +func (c CmdProgress) fiWriteCmd(fiw *textproto.FIWriter) error { return fiw.WriteLine("progress", c.Str) } @@ -122,7 +124,7 @@ type CmdGetMark struct { Mark int } -func (c *CmdGetMark) fiWriteCmd(fiw *FIWriter) error { +func (c CmdGetMark) fiWriteCmd(fiw *textproto.FIWriter) error { return fiw.WriteLine("get-mark", ":"+strconv.Itoa(c.Mark)) } @@ -130,17 +132,17 @@ type CmdCatBlob struct { DataRef string } -func (c *CmdCatBlob) fiWriteCmd(fiw *FIWriter) error { +func (c CmdCatBlob) fiWriteCmd(fiw *textproto.FIWriter) error { return fiw.WriteLine("cat-blob", c.DataRef) } // See FileLs for using ls inside of a commit type CmdLs struct { DataRef string - Path Path + Path textproto.Path } -func (c *CmdLs) fiWriteCmd(fiw *FIWriter) error { +func (c CmdLs) fiWriteCmd(fiw *textproto.FIWriter) error { return fiw.WriteLine("ls", c.DataRef, c.Path) } @@ -149,7 +151,7 @@ type CmdFeature struct { Argument string } -func (c *CmdFeature) fiWriteCmd(fiw *FIWriter) error { +func (c CmdFeature) fiWriteCmd(fiw *textproto.FIWriter) error { if c.Argument != "" { return fiw.WriteLine("feature", c.Feature+"="+c.Argument) } else { @@ -161,13 +163,13 @@ type CmdOption struct { Option string } -func (c *CmdOption) fiWriteCmd(fiw *FIWriter) error { +func (c CmdOption) fiWriteCmd(fiw *textproto.FIWriter) error { return fiw.WriteLine("option", c.Option) } type CmdDone struct{} -func (c *CmdDone) fiWriteCmd(fiw *FIWriter) error { +func (c CmdDone) fiWriteCmd(fiw *textproto.FIWriter) error { return fiw.WriteLine("done") } @@ -175,6 +177,6 @@ type CmdComment struct { Comment string } -func (c *CmdComment) fiWriteCmd(fiw *FIWriter) error { +func (c CmdComment) fiWriteCmd(fiw *textproto.FIWriter) error { return fiw.WriteLine("#" + c.Comment) } diff --git a/ezfiw.go b/ezfiw.go index 0143f48..03b4622 100644 --- a/ezfiw.go +++ b/ezfiw.go @@ -2,10 +2,12 @@ package libfastimport import ( "strconv" + + "git.lukeshu.com/go/libfastimport/textproto" ) type ezfiw struct { - fiw *FIWriter + fiw *textproto.FIWriter err error } diff --git a/fileactions.go b/fileactions.go index 2d81177..d45b982 100644 --- a/fileactions.go +++ b/fileactions.go @@ -1,26 +1,30 @@ package libfastimport +import ( + "git.lukeshu.com/go/libfastimport/textproto" +) + type FileAction interface { - fiWriteFA(*FIWriter) error + fiWriteFA(*textproto.FIWriter) error } type FileModify struct { - Mode Mode - Path Path + Mode textproto.Mode + Path textproto.Path DataRef string } -func (o FileModify) fiWriteFA(fiw *FIWriter) error { +func (o FileModify) fiWriteFA(fiw *textproto.FIWriter) error { return fiw.WriteLine("M", o.Mode, o.DataRef, o.Path) } type FileModifyInline struct { - Mode Mode - Path Path + Mode textproto.Mode + Path textproto.Path Data []byte } -func (o FileModifyInline) fiWriteFA(fiw *FIWriter) error { +func (o FileModifyInline) fiWriteFA(fiw *textproto.FIWriter) error { ez := &ezfiw{fiw: fiw} ez.WriteLine("M", o.Mode, "inline", o.Path) ez.WriteData(o.Data) @@ -28,19 +32,19 @@ func (o FileModifyInline) fiWriteFA(fiw *FIWriter) error { } type FileDelete struct { - Path Path + Path textproto.Path } -func (o FileDelete) fiWriteFA(fiw *FIWriter) error { +func (o FileDelete) fiWriteFA(fiw *textproto.FIWriter) error { return fiw.WriteLine("D", o.Path) } type FileCopy struct { - Src Path - Dst Path + Src textproto.Path + Dst textproto.Path } -func (o FileCopy) fiWriteFA(fiw *FIWriter) error { +func (o FileCopy) fiWriteFA(fiw *textproto.FIWriter) error { return fiw.WriteLine("C", o.Src, o.Dst) } @@ -49,13 +53,13 @@ type FileRename struct { Dst string } -func (o FileRename) fiWriteFA(fiw *FIWriter) error { +func (o FileRename) fiWriteFA(fiw *textproto.FIWriter) error { return fiw.WriteLine("R", o.Src, o.Dst) } type FileDeleteAll struct{} -func (o FileDeleteAll) fiWriteFA(fiw *FIWriter) error { +func (o FileDeleteAll) fiWriteFA(fiw *textproto.FIWriter) error { return fiw.WriteLine("deleteall") } @@ -64,7 +68,7 @@ type NoteModify struct { DataRef string } -func (o NoteModify) fiWriteFA(fiw *FIWriter) error { +func (o NoteModify) fiWriteFA(fiw *textproto.FIWriter) error { return fiw.WriteLine("N", o.DataRef, o.CommitIsh) } @@ -73,7 +77,7 @@ type NoteModifyInline struct { Data []byte } -func (o NoteModifyInline) fiWriteFA(fiw *FIWriter) error { +func (o NoteModifyInline) fiWriteFA(fiw *textproto.FIWriter) error { ez := &ezfiw{fiw: fiw} ez.WriteLine("N", "inline", o.CommitIsh) ez.WriteData(o.Data) @@ -82,9 +86,9 @@ func (o NoteModifyInline) fiWriteFA(fiw *FIWriter) error { // See CmdLs for using ls outside of a commit type FileLs struct { - Path Path + Path textproto.Path } -func (o FileLs) fiWriteFA(fiw *FIWriter) error { +func (o FileLs) fiWriteFA(fiw *textproto.FIWriter) error { return fiw.WriteLine("ls", o.Path) } diff --git a/frontend.go b/frontend.go new file mode 100644 index 0000000..73f6d73 --- /dev/null +++ b/frontend.go @@ -0,0 +1,68 @@ +package libfastimport + +import ( + "io" + "bufio" + + "git.lukeshu.com/go/libfastimport/textproto" +) + +type Frontend struct { + w *bufio.Writer + fiw *textproto.FIWriter + cbr *textproto.CatBlobReader +} + +func NewFrontend(w io.Writer, r io.Reader) *Frontend { + ret := Frontend{} + ret.w = bufio.NewWriter(w) + ret.fiw = textproto.NewFIWriter(ret.w) + if r != nil { + ret.cbr = textproto.NewCatBlobReader(r) + } + return &ret +} + +func (f *Frontend) Do(cmd Cmd) error { + err := cmd.fiWriteCmd(f.fiw) + if err != nil { + return err + } + return f.w.Flush() +} + +func (f *Frontend) GetMark(cmd CmdGetMark) (string, error) { + err := f.Do(cmd) + if err != nil { + return "", err + } + line, err := f.cbr.ReadLine() + if err != nil { + return "", err + } + return cbpGetMark(line) +} + +func (f *Frontend) CatBlob(cmd CmdCatBlob) (sha1 string, data string, err error) { + err = f.Do(cmd) + if err != nil { + return "", "", err + } + line, err := f.cbr.ReadLine() + if err != nil { + return "", "", err + } + return cbpCatBlob(line) +} + +func (f *Frontend) Ls(cmd CmdLs) (mode textproto.Mode, dataref string, path textproto.Path, err error) { + err = f.Do(cmd) + if err != nil { + return 0, "", "", err + } + line, err := f.cbr.ReadLine() + if err != nil { + return 0, "", "", err + } + return cbpLs(line) +} diff --git a/io.go b/io.go deleted file mode 100644 index d8a68bb..0000000 --- a/io.go +++ /dev/null @@ -1,152 +0,0 @@ -package libfastimport - -import ( - "fmt" - "bufio" - "bytes" - "io" - "strconv" -) - -type FIReader struct { - r *bufio.Reader -} - -func NewFIReader(r io.Reader) *FIReader { - return &FIReader{ - r: bufio.NewReader(r), - } -} - -func (fir *FIReader) ReadSlice() (line []byte, err error) { -retry: - line, err = fir.r.ReadSlice('\n') - if err != nil { - return - } - if len(line) == 1 { - goto retry - } - - if bytes.HasPrefix(line, []byte("data ")) { - if string(line[5:7]) == "<<" { - // Delimited format - delim := line[7 : len(line)-1] - suffix := []byte("\n" + string(delim) + "\n") - - _line := make([]byte, len(line)) - copy(_line, line) - line = _line - - for !bytes.HasSuffix(line, suffix) { - _line, err = fir.r.ReadSlice('\n') - line = append(line, _line...) - if err != nil { - return - } - } - } else { - // Exact byte count format - var size int - size, err = strconv.Atoi(string(line[5 : len(line)-1])) - if err != nil { - return - } - _line := make([]byte, size+len(line)) - copy(_line, line) - var n int - n, err = io.ReadFull(fir.r, _line[len(line):]) - line = _line[:n+len(line)] - } - } - return -} - -type FIWriter struct { - w io.Writer -} - -func NewFIWriter(w io.Writer) *FIWriter { - return &FIWriter{ - w: w, - } -} - -func (fiw *FIWriter) WriteLine(a ...interface{}) error { - _, err := fmt.Fprintln(fiw.w, a...) - return err -} - -func (fiw *FIWriter) WriteData(data []byte) error { - err := fiw.WriteLine("data", len(data)) - if err != nil { - return err - } - _, err = fiw.w.Write(data) - return err -} - -type CatBlobReader struct { - r *bufio.Reader -} - -func NewCatBlobReader(r io.Reader) *CatBlobReader { - return &CatBlobReader{ - r: bufio.NewReader(r), - } -} - -func (cbr *CatBlobReader) ReadSlice() (line []byte, err error) { -retry: - line, err = cbr.r.ReadSlice('\n') - if err != nil { - return - } - if len(line) == 1 { - goto retry - } - - // get-mark : LF - // cat-blob : SP 'blob' SP LF LF - // ls : SP ('blob' | 'tree' | 'commit') SP HT LF - // ls : 'missing' SP LF - - // decide if we have a cat-blob result - if len(line) <= 46 || string(line[40:46]) != " blob " { - return - } - for _, b := range line[:40] { - if !(('0' <= b && b <= '9') || ('a' <= b && b <= 'f')) { - return - } - } - // we have a cat-blob result - var size int - size, err = strconv.Atoi(string(line[46 : len(line)-1])) - if err != nil { - return - } - _line := make([]byte, len(line)+size+1) - copy(_line, line) - n, err := io.ReadFull(cbr.r, _line[len(line):]) - line = _line[:n+len(line)] - return -} - -type CatBlobWriter struct { - w io.Writer -} - -func (cbw *CatBlobWriter) WriteLine(a ...interface{}) error { - _, err := fmt.Fprintln(cbw.w, a...) - return err -} - -func (cbw *CatBlobWriter) WriteBlob(sha1 string, data []byte) error { - err := cbw.WriteLine(sha1, "blob", len(data)) - if err != nil { - return err - } - _, err = cbw.w.Write(data) - return err -} diff --git a/parse_catblob.go b/parse_catblob.go new file mode 100644 index 0000000..53f7d52 --- /dev/null +++ b/parse_catblob.go @@ -0,0 +1,97 @@ +package libfastimport + +import ( + "fmt" + "strings" + "strconv" + + "git.lukeshu.com/go/libfastimport/textproto" +) + +func cbpGetMark(line string) (string, error) { + if len(line) != 41 { + return "", fmt.Errorf("get-mark: short \\n: %q", line) + } + if line[40] != '\n' { + return "", fmt.Errorf("get-mark: malformed \\n: %q", line) + } + for _, b := range line[:40] { + if !(('0' <= b && b <= '9') || ('a' <= b && b <= 'f')) { + return "", fmt.Errorf("get-mark: malformed : %q", line[:40]) + } + } + return line[:40], nil +} + +func cbpCatBlob(full string) (sha1 string, data string, err error) { + // The format is: + // + // SP 'blob' SP LF + // LF + + if full[len(full)-1] != '\n' { + return "", "", fmt.Errorf("cat-blob: missing trailing newline") + } + + lf := strings.IndexByte(full, '\n') + if lf < 0 || lf == len(full)-1 { + return "", "", fmt.Errorf("cat-blob: malformed header: %q", full) + } + head := full[:lf] + data = full[lf+1:len(full)-1] + + if len(head) < 40+6+1 { + return "", "", fmt.Errorf("cat-blob: malformed header: %q", head) + } + + sha1 = head[:40] + for _, b := range sha1 { + if !(('0' <= b && b <= '9') || ('a' <= b && b <= 'f')) { + return "", "", fmt.Errorf("cat-blob: malformed : %q", sha1) + } + } + + if string(head[40:46]) != " blob " { + return "", "", fmt.Errorf("cat-blob: malformed header: %q", head) + } + + size, err := strconv.Atoi(head[46:]) + if err != nil { + return "", "", fmt.Errorf("cat-blob: malformed blob size: %v", err) + } + + if size != len(data) { + return "", "", fmt.Errorf("cat-blob: size header (%d) didn't match delivered size (%d)", size, len(data)) + } + + return sha1, data, err +} + +func cbpLs(line string) (mode textproto.Mode, dataref string, path textproto.Path, err error) { + // SP ('blob' | 'tree' | 'commit') SP HT LF + // or + // 'missing' SP LF + if line[len(line)-1] != '\n' { + return 0, "", "", fmt.Errorf("ls: missing trailing newline") + } + if strings.HasPrefix(line, "missing ") { + strPath := line[8:len(line)-1] + return 0, "", textproto.PathUnescape(strPath), nil + } else { + sp1 := strings.IndexByte(line, ' ') + sp2 := strings.IndexByte(line[sp1+1:], ' ') + ht := strings.IndexByte(line[sp2+1:], '\t') + if sp1 < 0 || sp2 < 0 || ht < 0 { + return 0, "", "", fmt.Errorf("ls: malformed line: %q", line) + } + strMode := line[:sp1] + strRef := line[sp2+1:ht] + strPath := line[ht+1:len(line)-1] + + nMode, err := strconv.ParseUint(strMode, 8, 18) + if err != nil { + return 0, "", "", err + } + return textproto.Mode(nMode), strRef, textproto.PathUnescape(strPath), nil + } +} diff --git a/read_catblob.go b/read_catblob.go deleted file mode 100644 index ed5cb14..0000000 --- a/read_catblob.go +++ /dev/null @@ -1,69 +0,0 @@ -package libfastimport - -import ( - "fmt" - "bytes" - "strconv" -) - -func CatBlobParseGetMark(dat []byte) (string, error) { - if len(dat) != 41 { - return "", fmt.Errorf("get-mark: short \\n: %q", string(dat)) - } - if dat[40] != '\n' { - return "", fmt.Errorf("get-mark: malformed \\n: %q", string(dat)) - } - for _, b := range dat[:40] { - if !(('0' <= b && b <= '9') || ('a' <= b && b <= 'f')) { - return "", fmt.Errorf("get-mark: malformed : %q", string(dat[:40])) - } - } - return string(dat[:40]), nil -} - -func CatBlobParseCatBlob(full []byte) (sha1 string, data []byte, err error) { - // The format is: - // - // SP 'blob' SP LF - // LF - - lf := bytes.IndexByte(full, '\n') - if lf < 0 || lf == len(full)-1 { - return "", nil, fmt.Errorf("cat-blob: malformed header: %q", string(full)) - } - 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)) - } - - sha1 = string(head[:40]) - for _, b := range sha1 { - if !(('0' <= b && b <= '9') || ('a' <= b && b <= 'f')) { - return "", nil, fmt.Errorf("cat-blob: malformed : %q", sha1) - } - } - - if string(head[40:46]) != " blob " { - return "", nil, fmt.Errorf("cat-blob: malformed header: %q", head) - } - - size, err := strconv.Atoi(string(head[46:])) - if err != nil { - return "", nil, fmt.Errorf("cat-blob: malformed blob size: %v", err) - } - - if size != len(data) { - return "", nil, fmt.Errorf("cat-blob: size header (%d) didn't match delivered size (%d)", size, len(data)) - } - - return sha1, data, err -} - -func CatBlobParseLs(dataref string, path string) error { - // SP ('blob' | 'tree' | 'commit') SP HT LF - // or - // 'missing' SP LF - return nil // TODO -} diff --git a/read_fastimport.go b/read_fastimport.go index ea10885..abafa4b 100644 --- a/read_fastimport.go +++ b/read_fastimport.go @@ -1,5 +1,9 @@ package libfastimport +import ( + "git.lukeshu.com/go/libfastimport/textproto" +) + type UnsupportedCommand string func (e UnsupportedCommand) Error() string { @@ -7,18 +11,18 @@ func (e UnsupportedCommand) Error() string { } type Parser struct { - fir *FIReader + fir *textproto.FIReader cmd chan Cmd } func (p *Parser) GetCmd() (Cmd, error) { for p.cmd == nil { - slice, err := p.fir.ReadSlice() + line, err := p.fir.ReadLine() if err != nil { return nil, err } - err = p.putSlice(slice) + err = p.putLine(line) if err != nil { return nil, err } @@ -26,23 +30,23 @@ func (p *Parser) GetCmd() (Cmd, error) { return <-p.cmd, nil } -func (p *Parser) putSlice(slice []byte) error { - if len(slice) < 1 { - return UnsupportedCommand(slice) +func (p *Parser) putLine(line string) error { + if len(line) < 1 { + return UnsupportedCommand(line) } - switch slice[0] { + switch line[0] { case '#': // comment case 'b': // blob case 'c': - if len(slice) < 2 { - return UnsupportedCommand(slice) + if len(line) < 2 { + return UnsupportedCommand(line) } - switch slice[1] { + switch line[1] { case 'o': // commit case 'h': // checkpoint case 'a': // cat-blob default: - return UnsupportedCommand(slice) + return UnsupportedCommand(line) } case 'd': // done case 'f': // feature @@ -53,7 +57,7 @@ func (p *Parser) putSlice(slice []byte) error { case 'r': // reset case 't': // tag default: - return UnsupportedCommand(slice) + return UnsupportedCommand(line) } return nil // TODO } diff --git a/textproto/io.go b/textproto/io.go new file mode 100644 index 0000000..af2cb19 --- /dev/null +++ b/textproto/io.go @@ -0,0 +1,146 @@ +package textproto + +import ( + "bufio" + "fmt" + "io" + "strconv" + "strings" +) + +type FIReader struct { + r *bufio.Reader +} + +func NewFIReader(r io.Reader) *FIReader { + return &FIReader{ + r: bufio.NewReader(r), + } +} + +func (fir *FIReader) ReadLine() (line string, err error) { +retry: + line, err = fir.r.ReadString('\n') + if err != nil { + return + } + if len(line) == 1 { + goto retry + } + + if strings.HasPrefix(line, "data ") { + if line[5:7] == "<<" { + // Delimited format + delim := line[7 : len(line)-1] + suffix := "\n" + delim + "\n" + + for !strings.HasSuffix(line, suffix) { + var _line string + _line, err = fir.r.ReadString('\n') + line += _line + if err != nil { + return + } + } + } else { + // Exact byte count format + var size int + size, err = strconv.Atoi(line[5 : len(line)-1]) + if err != nil { + return + } + data := make([]byte, size) + _, err = io.ReadFull(fir.r, data) + line += string(data) + } + } + return +} + +type FIWriter struct { + w io.Writer +} + +func NewFIWriter(w io.Writer) *FIWriter { + return &FIWriter{ + w: w, + } +} + +func (fiw *FIWriter) WriteLine(a ...interface{}) error { + _, err := fmt.Fprintln(fiw.w, a...) + return err +} + +func (fiw *FIWriter) WriteData(data []byte) error { + err := fiw.WriteLine("data", len(data)) + if err != nil { + return err + } + _, err = fiw.w.Write(data) + return err +} + +type CatBlobReader struct { + r *bufio.Reader +} + +func NewCatBlobReader(r io.Reader) *CatBlobReader { + return &CatBlobReader{ + r: bufio.NewReader(r), + } +} + +func (cbr *CatBlobReader) ReadLine() (line string, err error) { +retry: + line, err = cbr.r.ReadString('\n') + if err != nil { + return + } + if len(line) == 1 { + goto retry + } + + // get-mark : LF + // cat-blob : SP 'blob' SP LF LF + // ls : SP ('blob' | 'tree' | 'commit') SP HT LF + // ls : 'missing' SP LF + + // decide if we have a cat-blob result + if len(line) <= 46 || line[40:46] != " blob " { + return + } + for _, b := range line[:40] { + if !(('0' <= b && b <= '9') || ('a' <= b && b <= 'f')) { + return + } + } + // we have a cat-blob result + var size int + size, err = strconv.Atoi(line[46 : len(line)-1]) + if err != nil { + return + } + data := make([]byte, size+1) + _, err = io.ReadFull(cbr.r, data) + line += string(data[:size]) + return +} + +type CatBlobWriter struct { + w io.Writer +} + +func (cbw *CatBlobWriter) WriteLine(a ...interface{}) error { + _, err := fmt.Fprintln(cbw.w, a...) + return err +} + +func (cbw *CatBlobWriter) WriteBlob(sha1 string, data []byte) error { + err := cbw.WriteLine(sha1, "blob", len(data)) + if err != nil { + return err + } + _, err = cbw.w.Write(data) + return err +} diff --git a/textproto/types.go b/textproto/types.go new file mode 100644 index 0000000..2109517 --- /dev/null +++ b/textproto/types.go @@ -0,0 +1,65 @@ +package textproto + +import ( + "fmt" + "strings" + "time" +) + +type UserTime struct { + Name string + Email string + Time time.Time +} + +func (ut UserTime) String() string { + if ut.Name == "" { + return fmt.Sprintf("<%s> %d %s", + ut.Name, + ut.Email, + ut.Time.Unix(), + ut.Time.Format("-0700")) + } else { + return fmt.Sprintf("%s <%s> %d %s", + ut.Name, + ut.Email, + ut.Time.Unix(), + ut.Time.Format("-0700")) + } +} + +type Mode uint32 // 18 bits + +var ( + ModeFil = Mode(0100644) + ModeExe = Mode(0100755) + ModeSym = Mode(0120000) + ModeGit = Mode(0160000) + ModeDir = Mode(0040000) +) + +func (m Mode) String() string { + return fmt.Sprintf("%06o", m) +} + +func PathEscape(path Path) string { + if strings.HasPrefix(string(path), "\"") || strings.ContainsRune(string(path), '\n') { + return "\"" + strings.Replace(strings.Replace(strings.Replace(string(path), "\\", "\\\\", -1), "\"", "\\\"", -1), "\n", "\\n", -1) + "\"" + } else { + return string(path) + } +} + +func PathUnescape(epath string) Path { + if strings.HasPrefix(epath, "\"") { + return Path(strings.Replace(strings.Replace(strings.Replace(epath[1:len(epath)-1], "\\n", "\n", -1), "\\\"", "\"", -1), "\\\\", "\\", -1)) + } else { + return Path(epath) + } +} + +type Path string + +func (p Path) String() string { + return PathEscape(p) +} diff --git a/types.go b/types.go deleted file mode 100644 index 1ce0741..0000000 --- a/types.go +++ /dev/null @@ -1,65 +0,0 @@ -package libfastimport - -import ( - "fmt" - "strings" - "time" -) - -type UserTime struct { - Name string - Email string - Time time.Time -} - -func (ut UserTime) String() string { - if ut.Name == "" { - return fmt.Sprintf("<%s> %d %s", - ut.Name, - ut.Email, - ut.Time.Unix(), - ut.Time.Format("-0700")) - } else { - return fmt.Sprintf("%s <%s> %d %s", - ut.Name, - ut.Email, - ut.Time.Unix(), - ut.Time.Format("-0700")) - } -} - -type Mode uint32 // 18 bits - -var ( - ModeFil = Mode(0100644) - ModeExe = Mode(0100755) - ModeSym = Mode(0120000) - ModeGit = Mode(0160000) - ModeDir = Mode(0040000) -) - -func (m Mode) String() string { - return fmt.Sprintf("%06o", m) -} - -func PathEscape(path string) string { - if strings.HasPrefix(path, "\"") || strings.ContainsRune(path, '\n') { - return "\"" + strings.Replace(strings.Replace(strings.Replace(path, "\\", "\\\\", -1), "\"", "\\\"", -1), "\n", "\\n", -1) + "\"" - } else { - return path - } -} - -func PathUnescape(epath string) string { - if strings.HasPrefix(epath, "\"") { - return strings.Replace(strings.Replace(strings.Replace(epath[1:len(epath)-1], "\\n", "\n", -1), "\\\"", "\"", -1), "\\\\", "\\", -1) - } else { - return epath - } -} - -type Path string - -func (p Path) String() string { - return PathEscape(string(p)) -} -- cgit v1.2.3-54-g00ecf