mirror of
https://github.com/vee1e/gittuf.git
synced 2026-09-01 18:27:06 +00:00
fix: parse rename status
Signed-off-by: ayuxsh009 <1raj.aayush@gmail.com>
This commit is contained in:
parent
fa83a6d0de
commit
bfda5df850
2 changed files with 66 additions and 6 deletions
|
|
@ -71,6 +71,8 @@ func NewStatusCodeFromByte(s byte) (StatusCode, error) {
|
|||
return StatusCodeAdded, nil
|
||||
case 'D':
|
||||
return StatusCodeDeleted, nil
|
||||
case 'R':
|
||||
return StatusCodeRenamed, nil
|
||||
case 'C':
|
||||
return StatusCodeCopied, nil
|
||||
case 'U':
|
||||
|
|
@ -114,22 +116,26 @@ func (r *Repository) Status() (map[string]FileStatus, error) {
|
|||
|
||||
statuses := map[string]FileStatus{}
|
||||
|
||||
lines := strings.Split(output, string('\000'))
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
// `git status --porcelain=1 -z` emits NUL-separated tokens.
|
||||
// For rename/copy records, the source path is emitted as an additional
|
||||
// token after the main status token.
|
||||
tokens := strings.Split(output, string('\000'))
|
||||
for i := 0; i < len(tokens); i++ {
|
||||
token := tokens[i]
|
||||
if len(token) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// first two characters are status codes, find the corresponding
|
||||
// statuses
|
||||
xb := line[0]
|
||||
yb := line[1]
|
||||
xb := token[0]
|
||||
yb := token[1]
|
||||
// Note: we identify the status after inspecting the path so we can
|
||||
// provide better error messages
|
||||
|
||||
// then, we have a single space followed by the path, ignore space and
|
||||
// read in the rest as the filepath
|
||||
filePath := strings.TrimSpace(line[2:])
|
||||
filePath := strings.TrimSpace(token[2:])
|
||||
|
||||
xStatus, err := NewStatusCodeFromByte(xb)
|
||||
if err != nil {
|
||||
|
|
@ -144,6 +150,16 @@ func (r *Repository) Status() (map[string]FileStatus, error) {
|
|||
status := FileStatus{X: xStatus, Y: yStatus}
|
||||
|
||||
statuses[filePath] = status
|
||||
|
||||
// After splitting on NUL, rename/copy records have an additional token
|
||||
// for the source path immediately after the main token.
|
||||
if xStatus == StatusCodeRenamed || xStatus == StatusCodeCopied ||
|
||||
yStatus == StatusCodeRenamed || yStatus == StatusCodeCopied {
|
||||
if i+1 >= len(tokens) || len(tokens[i+1]) == 0 {
|
||||
return nil, fmt.Errorf("unable to parse rename/copy status for path '%s': missing source path", filePath)
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
return statuses, nil
|
||||
|
|
|
|||
|
|
@ -138,4 +138,48 @@ func TestStatus(t *testing.T) {
|
|||
statuses, err = repo.Status()
|
||||
assert.Nil(t, err)
|
||||
assert.Empty(t, statuses)
|
||||
|
||||
// Rename one of the existing files
|
||||
renamedPath := "baz"
|
||||
if _, err := repo.executor("mv", filename, renamedPath).executeString(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
statuses, err = repo.Status()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, map[string]FileStatus{
|
||||
renamedPath: {X: StatusCodeRenamed, Y: StatusCodeUnmodified},
|
||||
}, statuses)
|
||||
|
||||
// Commit the rename
|
||||
if _, err := repo.executor("commit", "-m", "Commit\n").executeString(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
statuses, err = repo.Status()
|
||||
assert.Nil(t, err)
|
||||
assert.Empty(t, statuses)
|
||||
|
||||
// Test that rename is parsed correctly alongside other changes in the same
|
||||
// status output. This validates that the NUL-separated source-path token
|
||||
// for the rename is consumed so subsequent entries are not mis-parsed.
|
||||
renamedPath2 := "quux"
|
||||
newFile := "qux"
|
||||
|
||||
if _, err := repo.executor("mv", renamedPath, renamedPath2).executeString(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(newFile, []byte("qux"), 0o644); err != nil { //nolint:gosec
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := repo.executor("add", newFile).executeString(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
statuses, err = repo.Status()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, map[string]FileStatus{
|
||||
renamedPath2: {X: StatusCodeRenamed, Y: StatusCodeUnmodified},
|
||||
newFile: {X: StatusCodeAdded, Y: StatusCodeUnmodified},
|
||||
}, statuses)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue