Merge pull request #1876 from dmcgowan/fs-include-parent-directories

Emit unmodified change events for directories
This commit is contained in:
Michael Crosby 2017-12-04 22:44:58 -05:00 committed by GitHub
commit 6a1ef90a6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 163 additions and 7 deletions

View File

@ -224,6 +224,8 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err
f1, f2 *currentPath f1, f2 *currentPath
rmdir string rmdir string
lastEmittedDir = string(filepath.Separator)
parents []os.FileInfo
) )
g.Go(func() error { g.Go(func() error {
defer close(c1) defer close(c1)
@ -258,7 +260,10 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err
continue continue
} }
var f os.FileInfo var (
f os.FileInfo
emit = true
)
k, p := pathChange(f1, f2) k, p := pathChange(f1, f2)
switch k { switch k {
case ChangeKindAdd: case ChangeKindAdd:
@ -294,17 +299,83 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err
f2 = nil f2 = nil
if same { if same {
if !isLinked(f) { if !isLinked(f) {
continue emit = false
} }
k = ChangeKindUnmodified k = ChangeKindUnmodified
} }
} }
if emit {
emittedDir, emitParents := commonParents(lastEmittedDir, p, parents)
for _, pf := range emitParents {
p := filepath.Join(emittedDir, pf.Name())
if err := changeFn(ChangeKindUnmodified, p, pf, nil); err != nil {
return err
}
emittedDir = p
}
if err := changeFn(k, p, f, nil); err != nil { if err := changeFn(k, p, f, nil); err != nil {
return err return err
} }
if f != nil && f.IsDir() {
lastEmittedDir = p
} else {
lastEmittedDir = emittedDir
}
parents = parents[:0]
} else if f.IsDir() {
lastEmittedDir, parents = commonParents(lastEmittedDir, p, parents)
parents = append(parents, f)
}
} }
return nil return nil
}) })
return g.Wait() return g.Wait()
} }
func commonParents(base, updated string, dirs []os.FileInfo) (string, []os.FileInfo) {
if basePrefix := makePrefix(base); strings.HasPrefix(updated, basePrefix) {
var (
parents []os.FileInfo
last = base
)
for _, d := range dirs {
next := filepath.Join(last, d.Name())
if strings.HasPrefix(updated, makePrefix(last)) {
parents = append(parents, d)
last = next
} else {
break
}
}
return base, parents
}
baseS := strings.Split(base, string(filepath.Separator))
updatedS := strings.Split(updated, string(filepath.Separator))
commonS := []string{string(filepath.Separator)}
min := len(baseS)
if len(updatedS) < min {
min = len(updatedS)
}
for i := 0; i < min; i++ {
if baseS[i] == updatedS[i] {
commonS = append(commonS, baseS[i])
} else {
break
}
}
return filepath.Join(commonS...), []os.FileInfo{}
}
func makePrefix(d string) string {
if d == "" || d[len(d)-1] != filepath.Separator {
return d + string(filepath.Separator)
}
return d
}

View File

@ -44,6 +44,7 @@ func TestSimpleDiff(t *testing.T) {
fstest.Remove("/etc/unexpected"), fstest.Remove("/etc/unexpected"),
) )
diff := []TestChange{ diff := []TestChange{
Unchanged("/etc"),
Modify("/etc/hosts"), Modify("/etc/hosts"),
Modify("/etc/profile"), Modify("/etc/profile"),
Delete("/etc/unexpected"), Delete("/etc/unexpected"),
@ -70,6 +71,7 @@ func TestDirectoryReplace(t *testing.T) {
fstest.CreateFile("/dir1/f2", []byte("Now file"), 0666), fstest.CreateFile("/dir1/f2", []byte("Now file"), 0666),
) )
diff := []TestChange{ diff := []TestChange{
Unchanged("/dir1"),
Add("/dir1/f11"), Add("/dir1/f11"),
Modify("/dir1/f2"), Modify("/dir1/f2"),
} }
@ -132,10 +134,13 @@ func TestParentDirectoryPermission(t *testing.T) {
fstest.CreateFile("/dir3/f", []byte("irrelevant"), 0644), fstest.CreateFile("/dir3/f", []byte("irrelevant"), 0644),
) )
diff := []TestChange{ diff := []TestChange{
Unchanged("/dir1"),
Add("/dir1/d"), Add("/dir1/d"),
Add("/dir1/d/f"), Add("/dir1/d/f"),
Add("/dir1/f"), Add("/dir1/f"),
Unchanged("/dir2"),
Add("/dir2/f"), Add("/dir2/f"),
Unchanged("/dir3"),
Add("/dir3/f"), Add("/dir3/f"),
} }
@ -184,6 +189,56 @@ func TestUpdateWithSameTime(t *testing.T) {
} }
} }
func TestUnchangedParent(t *testing.T) {
skipDiffTestOnWindows(t)
l1 := fstest.Apply(
fstest.CreateDir("/dir1", 0755),
fstest.CreateDir("/dir3", 0755),
fstest.CreateDir("/dir3/a", 0755),
fstest.CreateDir("/dir3/a/e", 0755),
fstest.CreateDir("/dir3/z", 0755),
)
l2 := fstest.Apply(
fstest.CreateDir("/dir1/a", 0755),
fstest.CreateFile("/dir1/a/b", []byte("irrelevant"), 0644),
fstest.CreateDir("/dir1/a/e", 0755),
fstest.CreateFile("/dir1/a/e/f", []byte("irrelevant"), 0644),
fstest.CreateFile("/dir1/f", []byte("irrelevant"), 0644),
fstest.CreateDir("/dir2", 0755),
fstest.CreateFile("/dir2/f", []byte("irrelevant"), 0644),
fstest.CreateFile("/dir3/a/b", []byte("irrelevant"), 0644),
fstest.CreateDir("/dir3/a/c", 0755),
fstest.CreateDir("/dir3/a/e/i", 0755),
fstest.CreateFile("/dir3/a/e/i/f", []byte("irrelevant"), 0644),
fstest.CreateFile("/dir3/f", []byte("irrelevant"), 0644),
fstest.CreateFile("/dir3/z/f", []byte("irrelevant"), 0644),
)
diff := []TestChange{
Unchanged("/dir1"),
Add("/dir1/a"),
Add("/dir1/a/b"),
Add("/dir1/a/e"),
Add("/dir1/a/e/f"),
Add("/dir1/f"),
Add("/dir2"),
Add("/dir2/f"),
Unchanged("/dir3"),
Unchanged("/dir3/a"),
Add("/dir3/a/b"),
Add("/dir3/a/c"),
Unchanged("/dir3/a/e"),
Add("/dir3/a/e/i"),
Add("/dir3/a/e/i/f"),
Add("/dir3/f"),
Unchanged("/dir3/z"),
Add("/dir3/z/f"),
}
if err := testDiffWithBase(l1, l2, diff); err != nil {
t.Fatalf("Failed diff with base: %+v", err)
}
}
// buildkit#172 // buildkit#172
func TestLchtimes(t *testing.T) { func TestLchtimes(t *testing.T) {
skipDiffTestOnWindows(t) skipDiffTestOnWindows(t)
@ -347,7 +402,7 @@ func diffString(c1, c2 []TestChange) string {
func changesString(c []TestChange) string { func changesString(c []TestChange) string {
strs := make([]string, len(c)) strs := make([]string, len(c))
for i := range c { for i := range c {
strs[i] = fmt.Sprintf("\t%s\t%s", c[i].Kind, c[i].Path) strs[i] = fmt.Sprintf("\t%-10s\t%s", c[i].Kind, c[i].Path)
} }
return strings.Join(strs, "\n") return strings.Join(strs, "\n")
} }
@ -372,3 +427,10 @@ func Modify(p string) TestChange {
Path: filepath.FromSlash(p), Path: filepath.FromSlash(p),
} }
} }
func Unchanged(p string) TestChange {
return TestChange{
Kind: ChangeKindUnmodified,
Path: filepath.FromSlash(p),
}
}

View File

@ -19,6 +19,7 @@ func FSSuite(t *testing.T, a TestApplier) {
t.Run("Deletion", makeTest(t, a, deletionTest)) t.Run("Deletion", makeTest(t, a, deletionTest))
t.Run("Update", makeTest(t, a, updateTest)) t.Run("Update", makeTest(t, a, updateTest))
t.Run("DirectoryPermission", makeTest(t, a, directoryPermissionsTest)) t.Run("DirectoryPermission", makeTest(t, a, directoryPermissionsTest))
t.Run("ParentDirectoryPermission", makeTest(t, a, parentDirectoryPermissionsTest))
t.Run("HardlinkUnmodified", makeTest(t, a, hardlinkUnmodified)) t.Run("HardlinkUnmodified", makeTest(t, a, hardlinkUnmodified))
t.Run("HardlinkBeforeUnmodified", makeTest(t, a, hardlinkBeforeUnmodified)) t.Run("HardlinkBeforeUnmodified", makeTest(t, a, hardlinkBeforeUnmodified))
t.Run("HardlinkBeforeModified", makeTest(t, a, hardlinkBeforeModified)) t.Run("HardlinkBeforeModified", makeTest(t, a, hardlinkBeforeModified))
@ -159,6 +160,28 @@ var (
), ),
} }
// parentDirectoryPermissionsTest covers directory permissions for updated
// files
parentDirectoryPermissionsTest = []Applier{
Apply(
CreateDir("/d1", 0700),
CreateDir("/d1/a", 0700),
CreateDir("/d1/a/b", 0700),
CreateDir("/d1/a/b/c", 0700),
CreateFile("/d1/a/b/f", []byte("content1"), 0644),
CreateDir("/d2", 0751),
CreateDir("/d2/a/b", 0751),
CreateDir("/d2/a/b/c", 0751),
CreateFile("/d2/a/b/f", []byte("content1"), 0644),
),
Apply(
CreateFile("/d1/a/b/f", []byte("content1"), 0644),
Chmod("/d1/a/b/c", 0700),
CreateFile("/d2/a/b/f", []byte("content2"), 0644),
Chmod("/d2/a/b/c", 0751),
),
}
hardlinkUnmodified = []Applier{ hardlinkUnmodified = []Applier{
baseApplier, baseApplier,
Apply( Apply(