-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for complicated filenames and file copies #61
Conversation
When filenames contain special characters, they are quoted, but not if they only contain spaces, meaning the 'git --diff' argument line becomes AMBIGUOUS. It is, however, possible to reconstruct the filenames using the extended headers. This fixes parsing of unquoted filenames with multiple spaces in them, quoted filenames with spaces in them, and diffs containing file copies.
Codecov Report
@@ Coverage Diff @@
## master #61 +/- ##
==========================================
+ Coverage 74.59% 77.34% +2.75%
==========================================
Files 4 4
Lines 429 490 +61
==========================================
+ Hits 320 379 +59
- Misses 62 63 +1
- Partials 47 48 +1
Continue to review full report at Codecov.
|
Hey @kwi-dk! Thanks for opening this PR and sorry for not leaving a comment earlier. I plan on reviewing this PR, but have to admit that I most likely will only get to it next week. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution! Especially for adding the tests.
I left a bunch of comments to make the code a bit more idiomatic. Let me know if you have bandwidth to incorporate them, otherwise I'm happyt to take the PR over.
diff/diff_test.go
Outdated
for _, input := range tests { | ||
_, _, err := readQuotedFilename(input) | ||
if err == nil { | ||
t.Errorf("readQuotedFilename(`%s`): expected error", input) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t.Errorf("readQuotedFilename(`%s`): expected error", input) | |
t.Errorf("readQuotedFilename(%q): expected error", input) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same concern about quoting as above.
diff/diff_test.go
Outdated
} | ||
|
||
func TestParseDiffGitArgs_Success(t *testing.T) { | ||
tests := []string{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above: I think structs
would make this easier to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to use structs.
diff/parse.go
Outdated
// readQuotedFilename extracts a quoted filename from the beginning of a string, | ||
// returning the unquoted filename and any remaining text after the filename. | ||
func readQuotedFilename(text string) (value string, remainder string, err error) { | ||
if text[0] != '"' { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if text[0] != '"' { | |
if text != "" && text[0] != '"' { |
Otherwise this will blow up when passed an empty string (another test case?)
diff/parse.go
Outdated
// returning the unquoted filename and any remaining text after the filename. | ||
func readQuotedFilename(text string) (value string, remainder string, err error) { | ||
if text[0] != '"' { | ||
panic("caller must ensure filename is quoted! " + text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be a panic
but an error
, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea here was that readQuotedFilename
is a private function, and its callers always ensure that text
starts with a quote. This test is thus just a sanity check; if it fails, it's a programming error, and a panic is fine.
But since this is evidently not clear at all, I'll just change to ordinary error handling, and silence the Codecov bot while I'm at it. :)
diff/parse.go
Outdated
} | ||
|
||
// parseDiffGitArgs extracts the two filenames from a 'diff --git' line. | ||
func parseDiffGitArgs(diffArgs string) (bool, string, string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more idiomatic signature for a function like this in Go would be this:
func parseDiffGitArgs(diffArgs string) (bool, string, string) { | |
func parseDiffGitArgs(diffArgs string) (string, string, bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
diff/parse.go
Outdated
// One or both filenames contain a space, but the names are | ||
// unquoted. Here, the 'diff --git' syntax is ambiguous, and | ||
// we have to obtain the filenames elsewhere (e.g. from the | ||
// chunk headers or extended headers). HOWEVER, if the file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// chunk headers or extended headers). HOWEVER, if the file | |
// hunk headers or extended headers). HOWEVER, if the file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay; turns out my GitHub notifications are broken. 😅
Feedback addressed in 28094f6.
diff/diff_test.go
Outdated
for _, input := range tests { | ||
_, _, err := readQuotedFilename(input) | ||
if err == nil { | ||
t.Errorf("readQuotedFilename(`%s`): expected error", input) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same concern about quoting as above.
diff/diff_test.go
Outdated
} | ||
|
||
func TestParseDiffGitArgs_Success(t *testing.T) { | ||
tests := []string{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to use structs.
diff/parse.go
Outdated
// returning the unquoted filename and any remaining text after the filename. | ||
func readQuotedFilename(text string) (value string, remainder string, err error) { | ||
if text[0] != '"' { | ||
panic("caller must ensure filename is quoted! " + text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea here was that readQuotedFilename
is a private function, and its callers always ensure that text
starts with a quote. This test is thus just a sanity check; if it fails, it's a programming error, and a panic is fine.
But since this is evidently not clear at all, I'll just change to ordinary error handling, and silence the Codecov bot while I'm at it. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thank you so much for this follow-up!
This fixes parsing of unquoted filenames with multiple spaces in them, quoted filenames with spaces in them, and diffs containing file copies (bug #48).
When filenames contain special characters, they are quoted, but not if they only contain spaces, meaning the
diff --git
argument line becomes ambiguous. It is, however, possible to reconstruct the filenames using the extended headers.