Skip to content

Commit

Permalink
Fix empty directory detection with common prefixes
Browse files Browse the repository at this point in the history
  • Loading branch information
angelini committed Oct 27, 2022
1 parent d0ea4a9 commit 6bbb290
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 11 deletions.
20 changes: 12 additions & 8 deletions pkg/diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import (
"github.com/gadget-inc/fsdiff/pkg/pb"
)

const (
Separator = string(filepath.Separator)
)

func isLink(mode uint32) bool {
return os.FileMode(mode)&os.ModeSymlink == os.ModeSymlink
}
Expand Down Expand Up @@ -46,7 +50,7 @@ func walkChan(dir string, ignores []string) <-chan *Message {

filepath.WalkDir(dir, func(path string, entry fs.DirEntry, err error) error {
if maybeEmptyDir != nil {
if !strings.HasPrefix(path, filepath.Join(dir, maybeEmptyDir.Path)) {
if !strings.HasPrefix(path, filepath.Join(dir, maybeEmptyDir.Path)+Separator) {
pushEmptyDir(maybeEmptyDir)
}
maybeEmptyDir = nil
Expand Down Expand Up @@ -92,7 +96,7 @@ func walkChan(dir string, ignores []string) <-chan *Message {

if entry.IsDir() {
maybeEmptyDir = &pb.Entry{
Path: fmt.Sprintf("%s/", relativePath),
Path: fmt.Sprintf("%s%s", relativePath, Separator),
Mode: uint32(os.ModeDir),
ModTime: info.ModTime().UnixNano(),
Size: 0,
Expand Down Expand Up @@ -152,8 +156,8 @@ func summaryChan(summary *pb.Summary) <-chan *Message {
}

func pathLessThan(left, right string) bool {
leftSplits := strings.Split(left, "/")
rightSplits := strings.Split(right, "/")
leftSplits := strings.Split(left, Separator)
rightSplits := strings.Split(right, Separator)

for idx, leftSplit := range leftSplits {
if idx >= len(rightSplits) {
Expand Down Expand Up @@ -185,8 +189,8 @@ func findLatestModTime(summary *pb.Summary) int64 {
return latest
}

func isEmptyDir(entry *pb.Entry) bool {
return strings.HasSuffix(entry.Path, "/")
func isEmptyDir(path string) bool {
return strings.HasSuffix(path, Separator)
}

func hashFile(path string) ([]byte, error) {
Expand Down Expand Up @@ -220,7 +224,7 @@ func hashEntry(dir string, entry *pb.Entry) ([]byte, error) {

path := filepath.Join(dir, entry.Path)

if isEmptyDir(entry) {
if isEmptyDir(entry.Path) {
hash = hashEmptyDir()
} else if isLink(entry.Mode) {
hash, err = hashLink(path)
Expand Down Expand Up @@ -283,7 +287,7 @@ func hashLatestEntries(dir string, summary *pb.Summary, diff *pb.Diff) error {
func removeOverlappingUpdates(updates []*pb.Update) []*pb.Update {
for i := len(updates) - 1; i >= 0; i-- {
update := updates[i]
if strings.HasSuffix(update.Path, "/") && update.Action == pb.Update_REMOVE {
if isEmptyDir(update.Path) && update.Action == pb.Update_REMOVE {
if len(updates) > i+1 && strings.HasPrefix(updates[i+1].Path, update.Path) {
updates = append(updates[:i], updates[i+1:]...)
}
Expand Down
36 changes: 33 additions & 3 deletions test/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func TestDiffWithIgnores(t *testing.T) {
updateTmpFiles(t, tmpDir, map[string]string{
"b": "b2",
".ignore_2": "new ignore",
}, []string{})
}, nil)

d2, s2, err := diff.Diff(tmpDir, []string{".ignore_1", ".ignore_2"}, s1)
if err != nil {
Expand Down Expand Up @@ -380,7 +380,7 @@ func TestDiffWithEmptyDirectories(t *testing.T) {
"e/f": "f2",
}, []string{"b/c", "b/d"})

d2, s2, err := diff.Diff(tmpDir, []string{}, s1)
d2, s2, err := diff.Diff(tmpDir, nil, s1)
if err != nil {
t.Fatalf("failed to run diff: %v", err)
}
Expand Down Expand Up @@ -413,7 +413,7 @@ func TestDiffWithFileMove(t *testing.T) {

moveFile(t, tmpDir, "a", "b")

d2, s2, err := diff.Diff(tmpDir, []string{}, s1)
d2, s2, err := diff.Diff(tmpDir, nil, s1)
if err != nil {
t.Fatalf("failed to run diff: %v", err)
}
Expand All @@ -427,3 +427,33 @@ func TestDiffWithFileMove(t *testing.T) {
"b": entry("a1"),
})
}

func TestDiffEmptyDirWithMatchingPrefix(t *testing.T) {
tmpDir := writeTmpFiles(t, map[string]string{})
defer os.RemoveAll(tmpDir)

createDir(t, tmpDir, "abc")

_, s1, err := diff.Diff(tmpDir, nil, nil)
if err != nil {
t.Fatalf("failed to run diff: %v", err)
}

updateTmpFiles(t, tmpDir, map[string]string{
"abcdef": "a1",
}, nil)

d2, s2, err := diff.Diff(tmpDir, nil, s1)
if err != nil {
t.Fatalf("failed to run diff: %v", err)
}

verifyUpdates(t, d2.Updates, map[string]pb.Update_Action{
"abcdef": pb.Update_ADD,
})

verifyEntries(t, s1.LatestModTime, s2.Entries, map[string]expectedEntry{
"abc/": directory(),
"abcdef": entry("a1"),
})
}

0 comments on commit 6bbb290

Please sign in to comment.