Merge pull request #1876 from dmcgowan/fs-include-parent-directories
Emit unmodified change events for directories
This commit is contained in:
commit
6a1ef90a6e
83
fs/diff.go
83
fs/diff.go
@ -222,8 +222,10 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err
|
|||||||
c1 = make(chan *currentPath)
|
c1 = make(chan *currentPath)
|
||||||
c2 = make(chan *currentPath)
|
c2 = make(chan *currentPath)
|
||||||
|
|
||||||
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,13 +299,35 @@ 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 err := changeFn(k, p, f, nil); err != nil {
|
if emit {
|
||||||
return err
|
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 {
|
||||||
|
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
|
||||||
@ -308,3 +335,47 @@ func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err
|
|||||||
|
|
||||||
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
|
||||||
|
}
|
||||||
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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(
|
||||||
|
Loading…
Reference in New Issue
Block a user