mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-23 19:47:07 +09:00
fix(gitdiff): unquote C-quoted paths from git diff-tree --raw (#39781)
`parseGitDiffTreeLine` (`services/gitdiff/git_diff_tree.go`) read `BasePath`/`HeadPath` straight from `git diff-tree --raw` output without undoing git's C-quoting, unlike its sibling `parseLsTreeLine` (`modules/git/parse.go`), which already does this with `strconv.Unquote`. This fix applies the same unquoting to both paths in the diff-tree parser. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
1 parent
76f8dc38e7
commit
c6069f8d9f
3 files changed
+40
-18
No files matched your search
+11
-7
@@ -56,13 +56,17 @@ func parseLsTreeLine(line []byte) (*LsTreeEntry, error) {
|
|||||||
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
|
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(entryName) > 0 && entryName[0] == '"' {
|
entry.Name, err = UnquoteDiffFilePath(string(entryName))
|
||||||
entry.Name, err = strconv.Unquote(string(entryName))
|
if err != nil {
|
||||||
if err != nil {
|
return nil, fmt.Errorf("invalid ls-tree output (invalid name): %q, err: %w", line, err)
|
||||||
return nil, fmt.Errorf("invalid ls-tree output (invalid name): %q, err: %w", line, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
entry.Name = string(entryName)
|
|
||||||
}
|
}
|
||||||
return entry, nil
|
return entry, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UnquoteDiffFilePath(path string) (string, error) {
|
||||||
|
// ref: see the document of git config's "core.quotepath"
|
||||||
|
if !strings.HasPrefix(path, `"`) {
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
return strconv.Unquote(path)
|
||||||
|
}
|
||||||
@@ -123,24 +123,19 @@ func validateGitDiffTreeArguments(ctx context.Context, gitRepo *git.Repository,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseGitDiffTree(gitOutput io.Reader) ([]*DiffTreeRecord, error) {
|
func parseGitDiffTree(gitOutput io.Reader) ([]*DiffTreeRecord, error) {
|
||||||
/*
|
/* The output of `git diff-tree --raw -r --find-renames` is of the form:
|
||||||
The output of `git diff-tree --raw -r --find-renames` is of the form:
|
:<old_mode> <new_mode> <old_sha> <new_sha> <status>\t<path>
|
||||||
|
|
||||||
:<old_mode> <new_mode> <old_sha> <new_sha> <status>\t<path>
|
or for renames:
|
||||||
|
:<old_mode> <new_mode> <old_sha> <new_sha> <status>\t<old_path>\t<new_path>
|
||||||
|
|
||||||
or for renames:
|
See: <https://git-scm.com/docs/git-diff-tree#_raw_output_format> for more details */
|
||||||
|
|
||||||
:<old_mode> <new_mode> <old_sha> <new_sha> <status>\t<old_path>\t<new_path>
|
|
||||||
|
|
||||||
See: <https://git-scm.com/docs/git-diff-tree#_raw_output_format> for more details
|
|
||||||
*/
|
|
||||||
results := make([]*DiffTreeRecord, 0)
|
results := make([]*DiffTreeRecord, 0)
|
||||||
|
|
||||||
lines := bufio.NewScanner(gitOutput)
|
lines := bufio.NewScanner(gitOutput)
|
||||||
for lines.Scan() {
|
for lines.Scan() {
|
||||||
line := lines.Text()
|
line := lines.Text()
|
||||||
|
if line == "" {
|
||||||
if len(line) == 0 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +188,13 @@ func parseGitDiffTreeLine(line string) (*DiffTreeRecord, error) {
|
|||||||
headPath = filePaths[0]
|
headPath = filePaths[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if basePath, err = git.UnquoteDiffFilePath(basePath); err != nil {
|
||||||
|
return nil, fmt.Errorf("unparsable output for diff-tree --raw: `%s`, invalid base path: %w", line, err)
|
||||||
|
}
|
||||||
|
if headPath, err = git.UnquoteDiffFilePath(headPath); err != nil {
|
||||||
|
return nil, fmt.Errorf("unparsable output for diff-tree --raw: `%s`, invalid head path: %w", line, err)
|
||||||
|
}
|
||||||
|
|
||||||
return &DiffTreeRecord{
|
return &DiffTreeRecord{
|
||||||
Status: status,
|
Status: status,
|
||||||
Score: score,
|
Score: score,
|
||||||
|
|||||||
@@ -324,6 +324,22 @@ func TestParseGitDiffTree(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// make sure our code can unquote paths no matter core.quotePath is true or false: quoted chars are like "\t" or "\{oct}"
|
||||||
|
Name: "file modified with a C-quoted path",
|
||||||
|
GitOutput: ":100644 100644 b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0 04fea06420ca60892f73becee3614f6d023a4b7f M\t" + `"\346\227\245\346\234\254\350\252\236\ttest.txt"`,
|
||||||
|
Expected: []*DiffTreeRecord{
|
||||||
|
{
|
||||||
|
Status: "modified",
|
||||||
|
HeadPath: "日本語\ttest.txt",
|
||||||
|
BasePath: "日本語\ttest.txt",
|
||||||
|
HeadMode: git.EntryModeBlob,
|
||||||
|
BaseMode: git.EntryModeBlob,
|
||||||
|
HeadBlobID: "04fea06420ca60892f73becee3614f6d023a4b7f",
|
||||||
|
BaseBlobID: "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "no changes",
|
Name: "no changes",
|
||||||
GitOutput: ``,
|
GitOutput: ``,
|
||||||
|
|||||||
Reference in new issue
Block a user