diff --git a/diff.go b/diff.go index ba364068..3dab3733 100644 --- a/diff.go +++ b/diff.go @@ -108,8 +108,10 @@ type DiffFile struct { // The type of the file. Type DiffFileType // The index (SHA1 hash) of the file. For a changed/new file, it is the new SHA, - // and for a deleted file it is the old SHA. + // and for a deleted file it becomes "000000". Index string + // OldIndex is the old index (SHA1 hash) of the file. + OldIndex string // The sections in the file. Sections []*DiffSection @@ -118,6 +120,9 @@ type DiffFile struct { oldName string + mode EntryMode + oldMode EntryMode + isBinary bool isSubmodule bool isIncomplete bool @@ -158,6 +163,16 @@ func (f *DiffFile) OldName() string { return f.oldName } +// Mode returns the mode of the file. +func (f *DiffFile) Mode() EntryMode { + return f.mode +} + +// OldMode returns the old mode of the file if it's changed. +func (f *DiffFile) OldMode() EntryMode { + return f.oldMode +} + // IsBinary returns true if the file is in binary format. func (f *DiffFile) IsBinary() bool { return f.isBinary @@ -268,8 +283,9 @@ func (p *diffParser) parseFileHeader() (*DiffFile, error) { } file := &DiffFile{ - Name: a, - Type: DiffFileChange, + Name: a, + oldName: b, + Type: DiffFileChange, } // Check file diff type and submodule @@ -291,9 +307,25 @@ checkType: case strings.HasPrefix(line, "new file"): file.Type = DiffFileAdd file.isSubmodule = strings.HasSuffix(line, " 160000") + fields := strings.Fields(line) + if len(fields) > 0 { + mode, _ := strconv.ParseUint(fields[len(fields)-1], 8, 64) + file.mode = EntryMode(mode) + if file.oldMode == 0 { + file.oldMode = file.mode + } + } case strings.HasPrefix(line, "deleted"): file.Type = DiffFileDelete file.isSubmodule = strings.HasSuffix(line, " 160000") + fields := strings.Fields(line) + if len(fields) > 0 { + mode, _ := strconv.ParseUint(fields[len(fields)-1], 8, 64) + file.mode = EntryMode(mode) + if file.oldMode == 0 { + file.oldMode = file.mode + } + } case strings.HasPrefix(line, "index"): // e.g. index ee791be..9997571 100644 fields := strings.Fields(line[6:]) shas := strings.Split(fields[0], "..") @@ -301,10 +333,12 @@ checkType: return nil, errors.New("malformed index: expect two SHAs in the form of ..") } - if file.IsDeleted() { - file.Index = shas[0] - } else { - file.Index = shas[1] + file.OldIndex = shas[0] + file.Index = shas[1] + if len(fields) > 1 { + mode, _ := strconv.ParseUint(fields[1], 8, 64) + file.mode = EntryMode(mode) + file.oldMode = EntryMode(mode) } break checkType case strings.HasPrefix(line, "similarity index "): @@ -316,8 +350,18 @@ checkType: if strings.HasSuffix(line, "100%") { break checkType } + case strings.HasPrefix(line, "new mode"): + fields := strings.Fields(line) + if len(fields) > 0 { + mode, _ := strconv.ParseUint(fields[len(fields)-1], 8, 64) + file.mode = EntryMode(mode) + } case strings.HasPrefix(line, "old mode"): - break checkType + fields := strings.Fields(line) + if len(fields) > 0 { + mode, _ := strconv.ParseUint(fields[len(fields)-1], 8, 64) + file.oldMode = EntryMode(mode) + } } } diff --git a/diff_test.go b/diff_test.go index 96f45d5a..eaa1ba93 100644 --- a/diff_test.go +++ b/diff_test.go @@ -144,6 +144,8 @@ func TestDiff(t *testing.T) { isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 100644, + oldMode: 100644, }, }, totalAdditions: 10, @@ -185,9 +187,10 @@ index 0000000..6b08f76 expDiff: &Diff{ Files: []*DiffFile{ { - Name: ".gitmodules", - Type: DiffFileAdd, - Index: "6abde17", + Name: ".gitmodules", + Type: DiffFileAdd, + Index: "6abde17", + OldIndex: "0000000", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -217,15 +220,18 @@ index 0000000..6b08f76 }, numAdditions: 3, numDeletions: 0, - oldName: "", + oldName: ".gitmodules", isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, { - Name: "gogs/docs-api", - Type: DiffFileAdd, - Index: "6b08f76", + Name: "gogs/docs-api", + Type: DiffFileAdd, + Index: "6b08f76", + OldIndex: "0000000", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -245,10 +251,12 @@ index 0000000..6b08f76 }, numAdditions: 1, numDeletions: 0, - oldName: "", + oldName: "gogs/docs-api", isBinary: false, isSubmodule: true, isIncomplete: false, + mode: 0160000, + oldMode: 0160000, }, }, totalAdditions: 4, @@ -273,9 +281,10 @@ index ee791be..9997571 100644 expDiff: &Diff{ Files: []*DiffFile{ { - Name: "pom.xml", - Type: DiffFileChange, - Index: "9997571", + Name: "pom.xml", + Type: DiffFileChange, + Index: "9997571", + OldIndex: "ee791be", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -330,10 +339,12 @@ index ee791be..9997571 100644 }, numAdditions: 1, numDeletions: 1, - oldName: "", + oldName: "pom.xml", isBinary: false, isSubmodule: false, isIncomplete: false, + oldMode: 0100644, + mode: 0100644, }, }, totalAdditions: 1, @@ -352,13 +363,16 @@ Binary files /dev/null and b/img/sourcegraph.png differ`, Name: "img/sourcegraph.png", Type: DiffFileAdd, Index: "2ce9188", + OldIndex: "0000000", Sections: nil, numAdditions: 0, numDeletions: 0, - oldName: "", + oldName: "img/sourcegraph.png", isBinary: true, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 0, @@ -375,14 +389,17 @@ index e69de29..0000000`, { Name: "fix.txt", Type: DiffFileDelete, - Index: "e69de29", + Index: "0000000", + OldIndex: "e69de29", Sections: nil, numAdditions: 0, numDeletions: 0, - oldName: "", + oldName: "fix.txt", isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 0, @@ -431,9 +448,10 @@ index b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0..ab80bda5dd90d8b42be25ac2c7a071b7 expDiff: &Diff{ Files: []*DiffFile{ { - Name: "dir/file.txt", - Type: DiffFileChange, - Index: "ab80bda5dd90d8b42be25ac2c7a071b722171f09", + Name: "dir/file.txt", + Type: DiffFileChange, + Index: "ab80bda5dd90d8b42be25ac2c7a071b722171f09", + OldIndex: "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -468,10 +486,12 @@ index b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0..ab80bda5dd90d8b42be25ac2c7a071b7 }, numAdditions: 3, numDeletions: 1, - oldName: "", + oldName: "dir/file.txt", isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 3, @@ -499,9 +519,10 @@ index ce53c7e..56a156b 100644 expDiff: &Diff{ Files: []*DiffFile{ { - Name: "src/app/tabs/friends/friends.module.ts", - Type: DiffFileRename, - Index: "56a156b", + Name: "src/app/tabs/friends/friends.module.ts", + Type: DiffFileRename, + Index: "56a156b", + OldIndex: "ce53c7e", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -557,6 +578,8 @@ index ce53c7e..56a156b 100644 numAdditions: 2, numDeletions: 2, oldName: "src/app/tabs/teacher/teacher.module.ts", + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 2, @@ -590,9 +613,10 @@ index 335db7ea..51d7543e 100644 expDiff: &Diff{ Files: []*DiffFile{ { - Name: ".travis.yml", - Type: DiffFileChange, - Index: "51d7543e", + Name: ".travis.yml", + Type: DiffFileChange, + Index: "51d7543e", + OldIndex: "335db7ea", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -652,10 +676,12 @@ index 335db7ea..51d7543e 100644 }, numAdditions: 0, numDeletions: 3, - oldName: "", + oldName: ".travis.yml", isBinary: false, isSubmodule: false, isIncomplete: true, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 0, @@ -677,9 +703,10 @@ index 0000000..6abde17 expDiff: &Diff{ Files: []*DiffFile{ { - Name: ".gitmodules", - Type: DiffFileAdd, - Index: "6abde17", + Name: ".gitmodules", + Type: DiffFileAdd, + Index: "6abde17", + OldIndex: "0000000", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -704,10 +731,12 @@ index 0000000..6abde17 }, numAdditions: 2, numDeletions: 0, - oldName: "", + oldName: ".gitmodules", isBinary: false, isSubmodule: false, isIncomplete: true, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 2, @@ -738,9 +767,10 @@ index 0000000..6b08f76 expDiff: &Diff{ Files: []*DiffFile{ { - Name: ".gitmodules", - Type: DiffFileAdd, - Index: "6abde17", + Name: ".gitmodules", + Type: DiffFileAdd, + Index: "6abde17", + OldIndex: "0000000", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -765,10 +795,12 @@ index 0000000..6b08f76 }, numAdditions: 2, numDeletions: 0, - oldName: "", + oldName: ".gitmodules", isBinary: false, isSubmodule: false, isIncomplete: true, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 2, @@ -776,6 +808,28 @@ index 0000000..6b08f76 isIncomplete: true, }, }, + { + input: `diff --git a/go.mod b/go.mod +old mode 100644 +new mode 100755`, + maxFileLines: 0, + maxLineChars: 0, + maxFiles: 1, + expDiff: &Diff{ + Files: []*DiffFile{ + { + Name: "go.mod", + oldName: "go.mod", + Type: DiffFileChange, + mode: 0100755, + oldMode: 0100644, + }, + }, + totalAdditions: 0, + totalDeletions: 0, + isIncomplete: false, + }, + }, } for _, test := range tests { t.Run("", func(t *testing.T) { diff --git a/repo_diff.go b/repo_diff.go index f7635f27..206ddeb0 100644 --- a/repo_diff.go +++ b/repo_diff.go @@ -97,17 +97,17 @@ func (r *Repository) RawDiff(rev string, diffType RawDiffFormat, w io.Writer, op switch diffType { case RawDiffNormal: if commit.ParentsCount() == 0 { - cmd.AddArgs("show", rev) + cmd.AddArgs("show", "--full-index", rev) } else { c, _ := commit.Parent(0) - cmd.AddArgs("diff", "-M", c.ID.String(), rev) + cmd.AddArgs("diff", "--full-index", "-M", c.ID.String(), rev) } case RawDiffPatch: if commit.ParentsCount() == 0 { - cmd.AddArgs("format-patch", "--no-signature", "--stdout", "--root", rev) + cmd.AddArgs("format-patch", "--full-index", "--no-signature", "--stdout", "--root", rev) } else { c, _ := commit.Parent(0) - cmd.AddArgs("format-patch", "--no-signature", "--stdout", rev+"..."+c.ID.String()) + cmd.AddArgs("format-patch", "--full-index", "--no-signature", "--stdout", rev+"..."+c.ID.String()) } default: return fmt.Errorf("invalid diffType: %s", diffType) @@ -135,5 +135,5 @@ func (r *Repository) DiffBinary(base, head string, opts ...DiffBinaryOptions) ([ opt = opts[0] } - return NewCommand("diff", "--binary", base, head).RunInDirWithTimeout(opt.Timeout, r.path) + return NewCommand("diff", "--full-index", "--binary", base, head).RunInDirWithTimeout(opt.Timeout, r.path) } diff --git a/repo_diff_test.go b/repo_diff_test.go index 2ddf5d5a..ec15c133 100644 --- a/repo_diff_test.go +++ b/repo_diff_test.go @@ -29,14 +29,17 @@ func TestRepository_Diff(t *testing.T) { { Name: "fix.txt", Type: DiffFileDelete, - Index: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + Index: "0000000000000000000000000000000000000000", + OldIndex: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", Sections: nil, numAdditions: 0, numDeletions: 0, - oldName: "", + oldName: "fix.txt", isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 0, @@ -49,9 +52,10 @@ func TestRepository_Diff(t *testing.T) { expDiff: &Diff{ Files: []*DiffFile{ { - Name: "README.txt", - Type: DiffFileAdd, - Index: "1e24b564bf2298965d8037af42d3ae15ad7d225a", + Name: "README.txt", + Type: DiffFileAdd, + Index: "1e24b564bf2298965d8037af42d3ae15ad7d225a", + OldIndex: "0000000000000000000000000000000000000000", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -131,15 +135,18 @@ func TestRepository_Diff(t *testing.T) { }, numAdditions: 11, numDeletions: 0, - oldName: "", + oldName: "README.txt", isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, { - Name: "resources/labels.properties", - Type: DiffFileAdd, - Index: "fbdcfef007c0c09061199e687087b18c3cf8e083", + Name: "resources/labels.properties", + Type: DiffFileAdd, + Index: "fbdcfef007c0c09061199e687087b18c3cf8e083", + OldIndex: "0000000000000000000000000000000000000000", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -177,15 +184,18 @@ func TestRepository_Diff(t *testing.T) { }, numAdditions: 4, numDeletions: 0, - oldName: "", + oldName: "resources/labels.properties", isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, { - Name: "src/Main.groovy", - Type: DiffFileAdd, - Index: "51680791956b43effdb2f16bccd2b4752d66078f", + Name: "src/Main.groovy", + Type: DiffFileAdd, + Index: "51680791956b43effdb2f16bccd2b4752d66078f", + OldIndex: "0000000000000000000000000000000000000000", Sections: []*DiffSection{ { Lines: []*DiffLine{ @@ -235,10 +245,12 @@ func TestRepository_Diff(t *testing.T) { }, numAdditions: 6, numDeletions: 0, - oldName: "", + oldName: "src/Main.groovy", isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 21, @@ -256,14 +268,17 @@ func TestRepository_Diff(t *testing.T) { { Name: "fix.txt", Type: DiffFileDelete, - Index: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + Index: "0000000000000000000000000000000000000000", + OldIndex: "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", Sections: nil, numAdditions: 0, numDeletions: 0, - oldName: "", + oldName: "fix.txt", isBinary: false, isSubmodule: false, isIncomplete: false, + mode: 0100644, + oldMode: 0100644, }, }, totalAdditions: 0, @@ -306,7 +321,7 @@ func TestRepository_RawDiff(t *testing.T) { diffType: RawDiffNormal, expOutput: `diff --git a/fix.txt b/fix.txt deleted file mode 100644 -index e69de29..0000000 +index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 `, }, { @@ -322,7 +337,7 @@ Subject: [PATCH] Delete fix.txt diff --git a/fix.txt b/fix.txt deleted file mode 100644 -index e69de29..0000000 +index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 `, }, { @@ -340,7 +355,7 @@ Date: Mon Nov 24 21:22:01 2008 -0700 diff --git a/README.txt b/README.txt new file mode 100644 -index 0000000..1e24b56 +index 0000000000000000000000000000000000000000..1e24b564bf2298965d8037af42d3ae15ad7d225a --- /dev/null +++ b/README.txt @@ -0,0 +1,11 @@ @@ -358,7 +373,7 @@ index 0000000..1e24b56 \ No newline at end of file diff --git a/resources/labels.properties b/resources/labels.properties new file mode 100644 -index 0000000..fbdcfef +index 0000000000000000000000000000000000000000..fbdcfef007c0c09061199e687087b18c3cf8e083 --- /dev/null +++ b/resources/labels.properties @@ -0,0 +1,4 @@ @@ -368,7 +383,7 @@ index 0000000..fbdcfef +cli.usage=This application doesn't use a command line interface diff --git a/src/Main.groovy b/src/Main.groovy new file mode 100644 -index 0000000..5168079 +index 0000000000000000000000000000000000000000..51680791956b43effdb2f16bccd2b4752d66078f --- /dev/null +++ b/src/Main.groovy @@ -0,0 +1,6 @@ @@ -401,7 +416,7 @@ Subject: [PATCH] Addition of the README and basic Groovy source samples. diff --git a/README.txt b/README.txt new file mode 100644 -index 0000000..1e24b56 +index 0000000000000000000000000000000000000000..1e24b564bf2298965d8037af42d3ae15ad7d225a --- /dev/null +++ b/README.txt @@ -0,0 +1,11 @@ @@ -419,7 +434,7 @@ index 0000000..1e24b56 \ No newline at end of file diff --git a/resources/labels.properties b/resources/labels.properties new file mode 100644 -index 0000000..fbdcfef +index 0000000000000000000000000000000000000000..fbdcfef007c0c09061199e687087b18c3cf8e083 --- /dev/null +++ b/resources/labels.properties @@ -0,0 +1,4 @@ @@ -429,7 +444,7 @@ index 0000000..fbdcfef +cli.usage=This application doesn't use a command line interface diff --git a/src/Main.groovy b/src/Main.groovy new file mode 100644 -index 0000000..5168079 +index 0000000000000000000000000000000000000000..51680791956b43effdb2f16bccd2b4752d66078f --- /dev/null +++ b/src/Main.groovy @@ -0,0 +1,6 @@ @@ -475,7 +490,7 @@ func TestRepository_DiffBinary(t *testing.T) { head: "4e59b72440188e7c2578299fc28ea425fbe9aece", expOutput: `diff --git a/.gitmodules b/.gitmodules new file mode 100644 -index 0000000..6abde17 +index 0000000000000000000000000000000000000000..6abde17f49a6d43df40366e57d8964fee0dfda11 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ @@ -484,7 +499,7 @@ index 0000000..6abde17 + url = https://github.com/gogs/docs-api.git diff --git a/gogs/docs-api b/gogs/docs-api new file mode 160000 -index 0000000..6b08f76 +index 0000000000000000000000000000000000000000..6b08f76a5313fa3d26859515b30aa17a5faa2807 --- /dev/null +++ b/gogs/docs-api @@ -0,0 +1 @@