Skip to content

Commit edfebe6

Browse files
zeripathlafriks
andauthored
Finally fix diff names (#13136)
* Finally fix diff names #12771 attempted to fix diff by avoiding the git diff line as it is possible to have an ambiguous line here. #12254 attempted to fix diff by assuming that names would quoted if they needed to be and if one was quoted then both would be. Both of these were wrong. I have now discovered `--src-prefix` and `--dst-prefix` which means that we can set this in such a way to force the git diff to always be unambiguous. Therefore this PR rollsback most of the changes in #12771 and uses these options to fix this. Signed-off-by: Andrew Thornton <art27@cantab.net> * Update services/gitdiff/gitdiff.go * Update services/gitdiff/gitdiff.go * Update modules/repofiles/temp_repo.go * fix test Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Lauris BH <lauris@nix.lv>
1 parent aa73b7b commit edfebe6

File tree

3 files changed

+81
-124
lines changed

3 files changed

+81
-124
lines changed

modules/repofiles/temp_repo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
292292
var diff *gitdiff.Diff
293293
var finalErr error
294294

295-
if err := git.NewCommand("diff-index", "--cached", "-p", "HEAD").
295+
if err := git.NewCommand("diff-index", "--src-prefix=\\a/", "--dst-prefix=\\b/", "--cached", "-p", "HEAD").
296296
RunInDirTimeoutEnvFullPipelineFunc(nil, 30*time.Second, t.basePath, stdoutWriter, stderr, nil, func(ctx context.Context, cancel context.CancelFunc) error {
297297
_ = stdoutWriter.Close()
298298
diff, finalErr = gitdiff.ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader)

services/gitdiff/gitdiff.go

Lines changed: 59 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -483,46 +483,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
483483
}
484484
line := linebuf.String()
485485

486-
if strings.HasPrefix(line, "--- ") {
487-
if line[4] == '"' {
488-
fmt.Sscanf(line[4:], "%q", &curFile.OldName)
489-
} else {
490-
curFile.OldName = line[4:]
491-
if strings.Contains(curFile.OldName, " ") {
492-
// Git adds a terminal \t if there is a space in the name
493-
curFile.OldName = curFile.OldName[:len(curFile.OldName)-1]
494-
}
495-
}
496-
if curFile.OldName[0:2] == "a/" {
497-
curFile.OldName = curFile.OldName[2:]
498-
}
499-
continue
500-
} else if strings.HasPrefix(line, "+++ ") {
501-
if line[4] == '"' {
502-
fmt.Sscanf(line[4:], "%q", &curFile.Name)
503-
} else {
504-
curFile.Name = line[4:]
505-
if strings.Contains(curFile.Name, " ") {
506-
// Git adds a terminal \t if there is a space in the name
507-
curFile.Name = curFile.Name[:len(curFile.Name)-1]
508-
}
509-
}
510-
if curFile.Name[0:2] == "b/" {
511-
curFile.Name = curFile.Name[2:]
512-
}
513-
curFile.IsRenamed = (curFile.Name != curFile.OldName) && !(curFile.IsCreated || curFile.IsDeleted)
514-
if curFile.IsDeleted {
515-
curFile.Name = curFile.OldName
516-
curFile.OldName = ""
517-
} else if curFile.IsCreated {
518-
curFile.OldName = ""
519-
}
520-
continue
521-
} else if len(line) == 0 {
522-
continue
523-
}
524-
525-
if strings.HasPrefix(line, "+++") || strings.HasPrefix(line, "---") || len(line) == 0 {
486+
if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") || len(line) == 0 {
526487
continue
527488
}
528489

@@ -610,10 +571,42 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
610571
break
611572
}
612573

574+
// Note: In case file name is surrounded by double quotes (it happens only in git-shell).
575+
// e.g. diff --git "a/xxx" "b/xxx"
576+
var a string
577+
var b string
578+
579+
rd := strings.NewReader(line[len(cmdDiffHead):])
580+
char, _ := rd.ReadByte()
581+
_ = rd.UnreadByte()
582+
if char == '"' {
583+
fmt.Fscanf(rd, "%q ", &a)
584+
if a[0] == '\\' {
585+
a = a[1:]
586+
}
587+
} else {
588+
fmt.Fscanf(rd, "%s ", &a)
589+
}
590+
char, _ = rd.ReadByte()
591+
_ = rd.UnreadByte()
592+
if char == '"' {
593+
fmt.Fscanf(rd, "%q", &b)
594+
if b[0] == '\\' {
595+
b = b[1:]
596+
}
597+
} else {
598+
fmt.Fscanf(rd, "%s", &b)
599+
}
600+
a = a[2:]
601+
b = b[2:]
602+
613603
curFile = &DiffFile{
614-
Index: len(diff.Files) + 1,
615-
Type: DiffFileChange,
616-
Sections: make([]*DiffSection, 0, 10),
604+
Name: b,
605+
OldName: a,
606+
Index: len(diff.Files) + 1,
607+
Type: DiffFileChange,
608+
Sections: make([]*DiffSection, 0, 10),
609+
IsRenamed: a != b,
617610
}
618611
diff.Files = append(diff.Files, curFile)
619612
curFileLinesCount = 0
@@ -622,7 +615,6 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
622615
curFileLFSPrefix = false
623616

624617
// Check file diff type and is submodule.
625-
loop:
626618
for {
627619
line, err := input.ReadString('\n')
628620
if err != nil {
@@ -633,67 +625,29 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
633625
}
634626
}
635627

636-
if curFile.Type != DiffFileRename {
637-
switch {
638-
case strings.HasPrefix(line, "new file"):
639-
curFile.Type = DiffFileAdd
640-
curFile.IsCreated = true
641-
case strings.HasPrefix(line, "deleted"):
642-
curFile.Type = DiffFileDel
643-
curFile.IsDeleted = true
644-
case strings.HasPrefix(line, "index"):
645-
curFile.Type = DiffFileChange
646-
case strings.HasPrefix(line, "similarity index 100%"):
647-
curFile.Type = DiffFileRename
648-
}
649-
if curFile.Type > 0 && curFile.Type != DiffFileRename {
650-
if strings.HasSuffix(line, " 160000\n") {
651-
curFile.IsSubmodule = true
652-
}
653-
break
654-
}
655-
} else {
656-
switch {
657-
case strings.HasPrefix(line, "rename from "):
658-
if line[12] == '"' {
659-
fmt.Sscanf(line[12:], "%q", &curFile.OldName)
660-
} else {
661-
curFile.OldName = line[12:]
662-
curFile.OldName = curFile.OldName[:len(curFile.OldName)-1]
663-
}
664-
case strings.HasPrefix(line, "rename to "):
665-
if line[10] == '"' {
666-
fmt.Sscanf(line[10:], "%q", &curFile.Name)
667-
} else {
668-
curFile.Name = line[10:]
669-
curFile.Name = curFile.Name[:len(curFile.Name)-1]
670-
}
671-
curFile.IsRenamed = true
672-
break loop
673-
case strings.HasPrefix(line, "copy from "):
674-
if line[10] == '"' {
675-
fmt.Sscanf(line[10:], "%q", &curFile.OldName)
676-
} else {
677-
curFile.OldName = line[10:]
678-
curFile.OldName = curFile.OldName[:len(curFile.OldName)-1]
679-
}
680-
case strings.HasPrefix(line, "copy to "):
681-
if line[8] == '"' {
682-
fmt.Sscanf(line[8:], "%q", &curFile.Name)
683-
} else {
684-
curFile.Name = line[8:]
685-
curFile.Name = curFile.Name[:len(curFile.Name)-1]
686-
}
687-
curFile.IsRenamed = true
688-
curFile.Type = DiffFileCopy
689-
break loop
690-
default:
691-
if strings.HasSuffix(line, " 160000\n") {
692-
curFile.IsSubmodule = true
693-
} else {
694-
break loop
695-
}
628+
switch {
629+
case strings.HasPrefix(line, "copy from "):
630+
curFile.IsRenamed = true
631+
curFile.Type = DiffFileCopy
632+
case strings.HasPrefix(line, "copy to "):
633+
curFile.IsRenamed = true
634+
curFile.Type = DiffFileCopy
635+
case strings.HasPrefix(line, "new file"):
636+
curFile.Type = DiffFileAdd
637+
curFile.IsCreated = true
638+
case strings.HasPrefix(line, "deleted"):
639+
curFile.Type = DiffFileDel
640+
curFile.IsDeleted = true
641+
case strings.HasPrefix(line, "index"):
642+
curFile.Type = DiffFileChange
643+
case strings.HasPrefix(line, "similarity index 100%"):
644+
curFile.Type = DiffFileRename
645+
}
646+
if curFile.Type > 0 {
647+
if strings.HasSuffix(line, " 160000\n") {
648+
curFile.IsSubmodule = true
696649
}
650+
break
697651
}
698652
}
699653
}
@@ -762,7 +716,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
762716
parentCommit, _ := commit.Parent(0)
763717
actualBeforeCommitID = parentCommit.ID.String()
764718
}
765-
diffArgs := []string{"diff", "-M"}
719+
diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"}
766720
if len(whitespaceBehavior) != 0 {
767721
diffArgs = append(diffArgs, whitespaceBehavior)
768722
}

services/gitdiff/gitdiff_test.go

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ func TestParsePatch_singlefile(t *testing.T) {
9090
tests := []testcase{
9191
{
9292
name: "readme.md2readme.md",
93-
gitdiff: `diff --git "a/README.md" "b/README.md"
94-
--- a/README.md
95-
+++ b/README.md
93+
gitdiff: `diff --git "\\a/README.md" "\\b/README.md"
94+
--- "\\a/README.md"
95+
+++ "\\b/README.md"
9696
@@ -1,3 +1,6 @@
9797
# gitea-github-migrator
9898
+
@@ -102,9 +102,10 @@ func TestParsePatch_singlefile(t *testing.T) {
102102
+ cut off
103103
+ cut off
104104
`,
105-
addition: 4,
106-
deletion: 1,
107-
filename: "README.md",
105+
addition: 4,
106+
deletion: 1,
107+
filename: "README.md",
108+
oldFilename: "README.md",
108109
},
109110
{
110111
name: "A \\ B",
@@ -119,16 +120,17 @@ func TestParsePatch_singlefile(t *testing.T) {
119120
Docker Pulls
120121
+ cut off
121122
+ cut off`,
122-
addition: 4,
123-
deletion: 1,
124-
filename: "A \\ B",
123+
addition: 4,
124+
deletion: 1,
125+
filename: "A \\ B",
126+
oldFilename: "A \\ B",
125127
},
126128
{
127129
name: "really weird filename",
128-
gitdiff: `diff --git a/a b/file b/a a/file b/a b/file b/a a/file
130+
gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/file b/a a/file"
129131
index d2186f1..f5c8ed2 100644
130-
--- a/a b/file b/a a/file
131-
+++ b/a b/file b/a a/file
132+
--- "\\a/a b/file b/a a/file"
133+
+++ "\\b/a b/file b/a a/file"
132134
@@ -1,3 +1,2 @@
133135
Create a weird file.
134136
@@ -141,10 +143,10 @@ index d2186f1..f5c8ed2 100644
141143
},
142144
{
143145
name: "delete file with blanks",
144-
gitdiff: `diff --git a/file with blanks b/file with blanks
146+
gitdiff: `diff --git "\\a/file with blanks" "\\b/file with blanks"
145147
deleted file mode 100644
146148
index 898651a..0000000
147-
--- a/file with blanks
149+
--- "\\a/file with blanks"
148150
+++ /dev/null
149151
@@ -1,5 +0,0 @@
150152
-a blank file
@@ -153,9 +155,10 @@ index 898651a..0000000
153155
-
154156
-the 5th line is the last
155157
`,
156-
addition: 0,
157-
deletion: 5,
158-
filename: "file with blanks",
158+
addition: 0,
159+
deletion: 5,
160+
filename: "file with blanks",
161+
oldFilename: "file with blanks",
159162
},
160163
{
161164
name: "rename a—as",
@@ -171,7 +174,7 @@ rename to "a\342\200\224as"
171174
},
172175
{
173176
name: "rename with spaces",
174-
gitdiff: `diff --git a/a b/file b/a a/file b/a b/a a/file b/b file
177+
gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/a a/file b/b file"
175178
similarity index 100%
176179
rename from a b/file b/a a/file
177180
rename to a b/a a/file b/b file

0 commit comments

Comments
 (0)