From 60632ea541ac6fc57c8158bf44c625c526e1b215 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 2 Nov 2016 09:35:03 -0400 Subject: fix git bindings --- src/edit/git.go | 111 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/edit/git.go b/src/edit/git.go index 183e84c..5679e49 100644 --- a/src/edit/git.go +++ b/src/edit/git.go @@ -11,7 +11,7 @@ import ( ) func GitPull() error { - return exec.Command("git", "pull").Run() + return exec.Command("git", "fetch").Run() } func GitPush() error { @@ -93,53 +93,88 @@ type GitFile struct { type GitTree map[string]GitFile -var ParseError = errors.New("git ls-tree parse error") +var ( + ParseErrorSpaces = errors.New("parse: git ls-tree: not enough spaces") + ParseErrorTab = errors.New("parse: git ls-tree: no tab") + ParseErrorNull = errors.New("parse: git ls-tree: no trailing null") +) -func GitLsTree() (GitTree, error) { - data, err := exec.Command("git", "ls-tree", "-trlz", "HEAD").Output() +func parseGitTreeLine(line []byte) (rname string, rfile GitFile, err error) { + // There is probably a better, shorter way of doing this + + // line = mode SP type SP hash SP size TAB name + a := bytes.SplitN(line, []byte{' '}, 4) + if len(a) != 4 { + err = ParseErrorSpaces + return + } + b := bytes.SplitN(a[3], []byte{'\t'}, 2) + if len(b) != 2 { + err = ParseErrorTab + return + } + fmode := a[0] + ftype := a[1] + fhash := a[2] + fsize := b[0] + fname := b[1] + + // convert datatypes + fmodeN, err := strconv.ParseInt(string(fmode), 10, 19) if err != nil { - return nil, err + return } - lines := bytes.Split(data, []byte{0}) - ret := make(GitTree, len(lines)-1) - for _, line := range lines[:len(ret)] { - // trim the trailing "\0" - if line[len(line)-1] != 0 { - return nil, ParseError - } - line = line[:len(line)-1] - // line = mode SP type SP hash SP size TAB name - a := bytes.SplitN(line, []byte{' '}, 4) - if len(a) != 4 { - return nil, ParseError - } - b := bytes.SplitN(a[3], []byte{'\t'}, 2) - if len(b) != 2 { - return nil, ParseError - } - fmode := a[0] - ftype := a[1] - fhash := a[2] - fsize := b[0] - fname := b[1] - fmodeN, err := strconv.ParseInt(string(fmode), 10, 19) + fsizeN := int64(-1) + fsizeS := string(bytes.TrimLeft(fsize, " ")) + if fsizeS != "-" { + fsizeN, err = strconv.ParseInt(fsizeS, 10, 64) if err != nil { - return nil, err + return } - fsizeN := int64(-1) - fsizeS := string(fsize) - if fsizeS != "-" { - fsizeN, err = strconv.ParseInt(fsizeS, 10, 64) - if err != nil { - return nil, err - } - } - ret[string(fname)] = GitFile{ + } + + rname = string(fname) + rfile = GitFile{ Mode: int32(fmodeN), Type: string(ftype), Hash: string(fhash), Size: fsizeN, + } + return +} + +func GitLsTree() (GitTree, error) { + // Get the root tree-ish + data, err := exec.Command("git", "rev-parse", "HEAD:").Output() + if err != nil { + return nil, err + } + treeish := string(bytes.TrimSuffix(data, []byte{'\n'})) + + // Recursively read said tree-ish + data, err = exec.Command("git", "ls-tree", "-trlz", treeish).Output() + if err != nil { + return nil, err + } + lines := bytes.Split(data, []byte{0}) + // The last line is empty line so se can ignore it + // (`len(lines)-1`), but because it doesn't include a line for + // the root tree, we have to +1. + ret := make(GitTree, len(lines)) + // Add the root tree + ret[""] = GitFile{ + Mode: int32(40000), + Type: "tree", + Hash: treeish, + Size: -1, + } + // Parse the lines from git ls-tree + for _, line := range lines[:len(ret)] { + name, file, err := parseGitTreeLine(line) + if err != nil { + return nil, err } + ret[name] = file } return ret, nil } -- cgit v1.2.3