From 6eaeb01ecf1471517bbd4882ab7450f4f45a6f1c Mon Sep 17 00:00:00 2001
From: Ethan Koenig <ethantkoenig@gmail.com>
Date: Sat, 10 Feb 2018 10:19:26 -0800
Subject: [PATCH] Update code.gitea.io/git (#3482)

---
 models/git_diff.go                | 12 ++++-
 models/repo_indexer.go            | 52 +++++--------------
 vendor/code.gitea.io/git/parse.go | 81 ++++++++++++++++++++++++++++++
 vendor/code.gitea.io/git/tree.go  | 83 +------------------------------
 vendor/vendor.json                |  6 +--
 5 files changed, 108 insertions(+), 126 deletions(-)
 create mode 100644 vendor/code.gitea.io/git/parse.go

diff --git a/models/git_diff.go b/models/git_diff.go
index 9e361d05f5..7b0b672ff1 100644
--- a/models/git_diff.go
+++ b/models/git_diff.go
@@ -14,6 +14,7 @@ import (
 	"io/ioutil"
 	"os"
 	"os/exec"
+	"strconv"
 	"strings"
 
 	"code.gitea.io/git"
@@ -368,8 +369,15 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
 			a := line[beg+2 : middle]
 			b := line[middle+3:]
 			if hasQuote {
-				a = string(git.UnescapeChars([]byte(a[1 : len(a)-1])))
-				b = string(git.UnescapeChars([]byte(b[1 : len(b)-1])))
+				var err error
+				a, err = strconv.Unquote(a)
+				if err != nil {
+					return nil, fmt.Errorf("Unquote: %v", err)
+				}
+				b, err = strconv.Unquote(b)
+				if err != nil {
+					return nil, fmt.Errorf("Unquote: %v", err)
+				}
 			}
 
 			curFile = &DiffFile{
diff --git a/models/repo_indexer.go b/models/repo_indexer.go
index ecd629587e..b4f7bf1bd7 100644
--- a/models/repo_indexer.go
+++ b/models/repo_indexer.go
@@ -231,43 +231,17 @@ func addDelete(filename string, repo *Repository, batch rupture.FlushingBatch) e
 }
 
 // parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
-func parseGitLsTreeOutput(stdout string) ([]fileUpdate, error) {
-	lines := strings.Split(stdout, "\n")
-	updates := make([]fileUpdate, 0, len(lines))
-	for _, line := range lines {
-		// expect line to be "<mode> <object-type> <object-sha>\t<filename>"
-		line = strings.TrimSpace(line)
-		if len(line) == 0 {
-			continue
+func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
+	entries, err := git.ParseTreeEntries(stdout)
+	if err != nil {
+		return nil, err
+	}
+	updates := make([]fileUpdate, len(entries))
+	for i, entry := range entries {
+		updates[i] = fileUpdate{
+			Filename: entry.Name(),
+			BlobSha:  entry.ID.String(),
 		}
-		firstSpaceIndex := strings.IndexByte(line, ' ')
-		if firstSpaceIndex < 0 {
-			log.Error(4, "Misformatted git ls-tree output: %s", line)
-			continue
-		}
-		tabIndex := strings.IndexByte(line, '\t')
-		if tabIndex < 42+firstSpaceIndex || tabIndex == len(line)-1 {
-			log.Error(4, "Misformatted git ls-tree output: %s", line)
-			continue
-		}
-		if objectType := line[firstSpaceIndex+1 : tabIndex-41]; objectType != "blob" {
-			// submodules appear as commit objects, we do not index submodules
-			continue
-		}
-
-		blobSha := line[tabIndex-40 : tabIndex]
-		filename := line[tabIndex+1:]
-		if filename[0] == '"' {
-			var err error
-			filename, err = strconv.Unquote(filename)
-			if err != nil {
-				return nil, err
-			}
-		}
-		updates = append(updates, fileUpdate{
-			Filename: filename,
-			BlobSha:  blobSha,
-		})
 	}
 	return updates, nil
 }
@@ -276,7 +250,7 @@ func parseGitLsTreeOutput(stdout string) ([]fileUpdate, error) {
 func genesisChanges(repo *Repository, revision string) (*repoChanges, error) {
 	var changes repoChanges
 	stdout, err := git.NewCommand("ls-tree", "--full-tree", "-r", revision).
-		RunInDir(repo.RepoPath())
+		RunInDirBytes(repo.RepoPath())
 	if err != nil {
 		return nil, err
 	}
@@ -327,11 +301,11 @@ func nonGenesisChanges(repo *Repository, revision string) (*repoChanges, error)
 
 	cmd := git.NewCommand("ls-tree", "--full-tree", revision, "--")
 	cmd.AddArguments(updatedFilenames...)
-	stdout, err = cmd.RunInDir(repo.RepoPath())
+	lsTreeStdout, err := cmd.RunInDirBytes(repo.RepoPath())
 	if err != nil {
 		return nil, err
 	}
-	changes.Updates, err = parseGitLsTreeOutput(stdout)
+	changes.Updates, err = parseGitLsTreeOutput(lsTreeStdout)
 	return &changes, err
 }
 
diff --git a/vendor/code.gitea.io/git/parse.go b/vendor/code.gitea.io/git/parse.go
new file mode 100644
index 0000000000..5c964f16ee
--- /dev/null
+++ b/vendor/code.gitea.io/git/parse.go
@@ -0,0 +1,81 @@
+// Copyright 2018 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bytes"
+	"fmt"
+	"strconv"
+)
+
+// ParseTreeEntries parses the output of a `git ls-tree` command.
+func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
+	return parseTreeEntries(data, nil)
+}
+
+func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
+	entries := make([]*TreeEntry, 0, 10)
+	for pos := 0; pos < len(data); {
+		// expect line to be of the form "<mode> <type> <sha>\t<filename>"
+		entry := new(TreeEntry)
+		entry.ptree = ptree
+		if pos+6 > len(data) {
+			return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data))
+		}
+		switch string(data[pos : pos+6]) {
+		case "100644":
+			entry.mode = EntryModeBlob
+			entry.Type = ObjectBlob
+			pos += 12 // skip over "100644 blob "
+		case "100755":
+			entry.mode = EntryModeExec
+			entry.Type = ObjectBlob
+			pos += 12 // skip over "100755 blob "
+		case "120000":
+			entry.mode = EntryModeSymlink
+			entry.Type = ObjectBlob
+			pos += 12 // skip over "120000 blob "
+		case "160000":
+			entry.mode = EntryModeCommit
+			entry.Type = ObjectCommit
+			pos += 14 // skip over "160000 object "
+		case "040000":
+			entry.mode = EntryModeTree
+			entry.Type = ObjectTree
+			pos += 12 // skip over "040000 tree "
+		default:
+			return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+6]))
+		}
+
+		if pos+40 > len(data) {
+			return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data))
+		}
+		id, err := NewIDFromString(string(data[pos : pos+40]))
+		if err != nil {
+			return nil, fmt.Errorf("Invalid ls-tree output: %v", err)
+		}
+		entry.ID = id
+		pos += 41 // skip over sha and trailing space
+
+		end := pos + bytes.IndexByte(data[pos:], '\n')
+		if end < pos {
+			return nil, fmt.Errorf("Invalid ls-tree output: %s", string(data))
+		}
+
+		// In case entry name is surrounded by double quotes(it happens only in git-shell).
+		if data[pos] == '"' {
+			entry.name, err = strconv.Unquote(string(data[pos:end]))
+			if err != nil {
+				return nil, fmt.Errorf("Invalid ls-tree output: %v", err)
+			}
+		} else {
+			entry.name = string(data[pos:end])
+		}
+
+		pos = end + 1
+		entries = append(entries, entry)
+	}
+	return entries, nil
+}
diff --git a/vendor/code.gitea.io/git/tree.go b/vendor/code.gitea.io/git/tree.go
index 05e7afd127..4654dac30e 100644
--- a/vendor/code.gitea.io/git/tree.go
+++ b/vendor/code.gitea.io/git/tree.go
@@ -5,8 +5,6 @@
 package git
 
 import (
-	"bytes"
-	"fmt"
 	"strings"
 )
 
@@ -30,84 +28,6 @@ func NewTree(repo *Repository, id SHA1) *Tree {
 	}
 }
 
-var escapeChar = []byte("\\")
-
-// UnescapeChars reverses escaped characters.
-func UnescapeChars(in []byte) []byte {
-	if bytes.Index(in, escapeChar) == -1 {
-		return in
-	}
-
-	endIdx := len(in) - 1
-	isEscape := false
-	out := make([]byte, 0, endIdx+1)
-	for i := range in {
-		if in[i] == '\\' && !isEscape {
-			isEscape = true
-			continue
-		}
-		isEscape = false
-		out = append(out, in[i])
-	}
-	return out
-}
-
-// parseTreeData parses tree information from the (uncompressed) raw
-// data from the tree object.
-func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
-	entries := make([]*TreeEntry, 0, 10)
-	l := len(data)
-	pos := 0
-	for pos < l {
-		entry := new(TreeEntry)
-		entry.ptree = tree
-		step := 6
-		switch string(data[pos : pos+step]) {
-		case "100644":
-			entry.mode = EntryModeBlob
-			entry.Type = ObjectBlob
-		case "100755":
-			entry.mode = EntryModeExec
-			entry.Type = ObjectBlob
-		case "120000":
-			entry.mode = EntryModeSymlink
-			entry.Type = ObjectBlob
-		case "160000":
-			entry.mode = EntryModeCommit
-			entry.Type = ObjectCommit
-
-			step = 8
-		case "040000":
-			entry.mode = EntryModeTree
-			entry.Type = ObjectTree
-		default:
-			return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+step]))
-		}
-		pos += step + 6 // Skip string type of entry type.
-
-		step = 40
-		id, err := NewIDFromString(string(data[pos : pos+step]))
-		if err != nil {
-			return nil, err
-		}
-		entry.ID = id
-		pos += step + 1 // Skip half of SHA1.
-
-		step = bytes.IndexByte(data[pos:], '\n')
-
-		// In case entry name is surrounded by double quotes(it happens only in git-shell).
-		if data[pos] == '"' {
-			entry.name = string(UnescapeChars(data[pos+1 : pos+step-1]))
-		} else {
-			entry.name = string(data[pos : pos+step])
-		}
-
-		pos += step + 1
-		entries = append(entries, entry)
-	}
-	return entries, nil
-}
-
 // SubTree get a sub tree by the sub dir path
 func (t *Tree) SubTree(rpath string) (*Tree, error) {
 	if len(rpath) == 0 {
@@ -142,12 +62,11 @@ func (t *Tree) ListEntries() (Entries, error) {
 	if t.entriesParsed {
 		return t.entries, nil
 	}
-	t.entriesParsed = true
 
 	stdout, err := NewCommand("ls-tree", t.ID.String()).RunInDirBytes(t.repo.Path)
 	if err != nil {
 		return nil, err
 	}
-	t.entries, err = parseTreeData(t, stdout)
+	t.entries, err = parseTreeEntries(stdout, t)
 	return t.entries, err
 }
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 520cf8e22b..7397cac40a 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -3,10 +3,10 @@
 	"ignore": "test appengine",
 	"package": [
 		{
-			"checksumSHA1": "Gz+a5Qo4PCiB/Gf2f02v8HEAxDM=",
+			"checksumSHA1": "j6YyQxuOYRs94MVEamvnbE6ZtD0=",
 			"path": "code.gitea.io/git",
-			"revision": "6798d0f202cdc7187c00a467b586a4bdee27e8c9",
-			"revisionTime": "2018-01-14T14:37:32Z"
+			"revision": "827f97aaaa6a4ab5c31b1b799c56687a8cf6aade",
+			"revisionTime": "2018-02-10T03:05:43Z"
 		},
 		{
 			"checksumSHA1": "Qtq0kW+BnpYMOriaoCjMa86WGG8=",