Browse code

Move Change to the archive package, and fix a leftover merge in Container.Inject()

Solomon Hykes authored on 2013/11/08 09:35:26
Showing 8 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,208 @@
0
+package archive
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+	"path/filepath"
6
+	"strings"
7
+	"syscall"
8
+)
9
+
10
+type ChangeType int
11
+
12
+const (
13
+	ChangeModify = iota
14
+	ChangeAdd
15
+	ChangeDelete
16
+)
17
+
18
+type Change struct {
19
+	Path string
20
+	Kind ChangeType
21
+}
22
+
23
+func (change *Change) String() string {
24
+	var kind string
25
+	switch change.Kind {
26
+	case ChangeModify:
27
+		kind = "C"
28
+	case ChangeAdd:
29
+		kind = "A"
30
+	case ChangeDelete:
31
+		kind = "D"
32
+	}
33
+	return fmt.Sprintf("%s %s", kind, change.Path)
34
+}
35
+
36
+func Changes(layers []string, rw string) ([]Change, error) {
37
+	var changes []Change
38
+	err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
39
+		if err != nil {
40
+			return err
41
+		}
42
+
43
+		// Rebase path
44
+		path, err = filepath.Rel(rw, path)
45
+		if err != nil {
46
+			return err
47
+		}
48
+		path = filepath.Join("/", path)
49
+
50
+		// Skip root
51
+		if path == "/" {
52
+			return nil
53
+		}
54
+
55
+		// Skip AUFS metadata
56
+		if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
57
+			return err
58
+		}
59
+
60
+		change := Change{
61
+			Path: path,
62
+		}
63
+
64
+		// Find out what kind of modification happened
65
+		file := filepath.Base(path)
66
+		// If there is a whiteout, then the file was removed
67
+		if strings.HasPrefix(file, ".wh.") {
68
+			originalFile := file[len(".wh."):]
69
+			change.Path = filepath.Join(filepath.Dir(path), originalFile)
70
+			change.Kind = ChangeDelete
71
+		} else {
72
+			// Otherwise, the file was added
73
+			change.Kind = ChangeAdd
74
+
75
+			// ...Unless it already existed in a top layer, in which case, it's a modification
76
+			for _, layer := range layers {
77
+				stat, err := os.Stat(filepath.Join(layer, path))
78
+				if err != nil && !os.IsNotExist(err) {
79
+					return err
80
+				}
81
+				if err == nil {
82
+					// The file existed in the top layer, so that's a modification
83
+
84
+					// However, if it's a directory, maybe it wasn't actually modified.
85
+					// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
86
+					if stat.IsDir() && f.IsDir() {
87
+						if f.Size() == stat.Size() && f.Mode() == stat.Mode() && f.ModTime() == stat.ModTime() {
88
+							// Both directories are the same, don't record the change
89
+							return nil
90
+						}
91
+					}
92
+					change.Kind = ChangeModify
93
+					break
94
+				}
95
+			}
96
+		}
97
+
98
+		// Record change
99
+		changes = append(changes, change)
100
+		return nil
101
+	})
102
+	if err != nil && !os.IsNotExist(err) {
103
+		return nil, err
104
+	}
105
+	return changes, nil
106
+}
107
+
108
+func ChangesDirs(newDir, oldDir string) ([]Change, error) {
109
+	var changes []Change
110
+	err := filepath.Walk(newDir, func(newPath string, f os.FileInfo, err error) error {
111
+		if err != nil {
112
+			return err
113
+		}
114
+
115
+		var newStat syscall.Stat_t
116
+		err = syscall.Lstat(newPath, &newStat)
117
+		if err != nil {
118
+			return err
119
+		}
120
+
121
+		// Rebase path
122
+		relPath, err := filepath.Rel(newDir, newPath)
123
+		if err != nil {
124
+			return err
125
+		}
126
+		relPath = filepath.Join("/", relPath)
127
+
128
+		// Skip root
129
+		if relPath == "/" || relPath == "/.docker-id" {
130
+			return nil
131
+		}
132
+
133
+		change := Change{
134
+			Path: relPath,
135
+		}
136
+
137
+		oldPath := filepath.Join(oldDir, relPath)
138
+
139
+		var oldStat = &syscall.Stat_t{}
140
+		err = syscall.Lstat(oldPath, oldStat)
141
+		if err != nil {
142
+			if !os.IsNotExist(err) {
143
+				return err
144
+			}
145
+			oldStat = nil
146
+		}
147
+
148
+		if oldStat == nil {
149
+			change.Kind = ChangeAdd
150
+			changes = append(changes, change)
151
+		} else {
152
+			if oldStat.Ino != newStat.Ino ||
153
+				oldStat.Mode != newStat.Mode ||
154
+				oldStat.Uid != newStat.Uid ||
155
+				oldStat.Gid != newStat.Gid ||
156
+				oldStat.Rdev != newStat.Rdev ||
157
+				oldStat.Size != newStat.Size ||
158
+				oldStat.Blocks != newStat.Blocks ||
159
+				oldStat.Mtim != newStat.Mtim ||
160
+				oldStat.Ctim != newStat.Ctim {
161
+				change.Kind = ChangeModify
162
+				changes = append(changes, change)
163
+			}
164
+		}
165
+
166
+		return nil
167
+	})
168
+	if err != nil {
169
+		return nil, err
170
+	}
171
+	err = filepath.Walk(oldDir, func(oldPath string, f os.FileInfo, err error) error {
172
+		if err != nil {
173
+			return err
174
+		}
175
+
176
+		// Rebase path
177
+		relPath, err := filepath.Rel(oldDir, oldPath)
178
+		if err != nil {
179
+			return err
180
+		}
181
+		relPath = filepath.Join("/", relPath)
182
+
183
+		// Skip root
184
+		if relPath == "/" {
185
+			return nil
186
+		}
187
+
188
+		change := Change{
189
+			Path: relPath,
190
+		}
191
+
192
+		newPath := filepath.Join(newDir, relPath)
193
+
194
+		var newStat = &syscall.Stat_t{}
195
+		err = syscall.Lstat(newPath, newStat)
196
+		if err != nil && os.IsNotExist(err) {
197
+			change.Kind = ChangeDelete
198
+			changes = append(changes, change)
199
+		}
200
+
201
+		return nil
202
+	})
203
+	if err != nil {
204
+		return nil, err
205
+	}
206
+	return changes, nil
207
+}
0 208
deleted file mode 100644
... ...
@@ -1,208 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"fmt"
5
-	"os"
6
-	"path/filepath"
7
-	"strings"
8
-	"syscall"
9
-)
10
-
11
-type ChangeType int
12
-
13
-const (
14
-	ChangeModify = iota
15
-	ChangeAdd
16
-	ChangeDelete
17
-)
18
-
19
-type Change struct {
20
-	Path string
21
-	Kind ChangeType
22
-}
23
-
24
-func (change *Change) String() string {
25
-	var kind string
26
-	switch change.Kind {
27
-	case ChangeModify:
28
-		kind = "C"
29
-	case ChangeAdd:
30
-		kind = "A"
31
-	case ChangeDelete:
32
-		kind = "D"
33
-	}
34
-	return fmt.Sprintf("%s %s", kind, change.Path)
35
-}
36
-
37
-func Changes(layers []string, rw string) ([]Change, error) {
38
-	var changes []Change
39
-	err := filepath.Walk(rw, func(path string, f os.FileInfo, err error) error {
40
-		if err != nil {
41
-			return err
42
-		}
43
-
44
-		// Rebase path
45
-		path, err = filepath.Rel(rw, path)
46
-		if err != nil {
47
-			return err
48
-		}
49
-		path = filepath.Join("/", path)
50
-
51
-		// Skip root
52
-		if path == "/" {
53
-			return nil
54
-		}
55
-
56
-		// Skip AUFS metadata
57
-		if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
58
-			return err
59
-		}
60
-
61
-		change := Change{
62
-			Path: path,
63
-		}
64
-
65
-		// Find out what kind of modification happened
66
-		file := filepath.Base(path)
67
-		// If there is a whiteout, then the file was removed
68
-		if strings.HasPrefix(file, ".wh.") {
69
-			originalFile := file[len(".wh."):]
70
-			change.Path = filepath.Join(filepath.Dir(path), originalFile)
71
-			change.Kind = ChangeDelete
72
-		} else {
73
-			// Otherwise, the file was added
74
-			change.Kind = ChangeAdd
75
-
76
-			// ...Unless it already existed in a top layer, in which case, it's a modification
77
-			for _, layer := range layers {
78
-				stat, err := os.Stat(filepath.Join(layer, path))
79
-				if err != nil && !os.IsNotExist(err) {
80
-					return err
81
-				}
82
-				if err == nil {
83
-					// The file existed in the top layer, so that's a modification
84
-
85
-					// However, if it's a directory, maybe it wasn't actually modified.
86
-					// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
87
-					if stat.IsDir() && f.IsDir() {
88
-						if f.Size() == stat.Size() && f.Mode() == stat.Mode() && f.ModTime() == stat.ModTime() {
89
-							// Both directories are the same, don't record the change
90
-							return nil
91
-						}
92
-					}
93
-					change.Kind = ChangeModify
94
-					break
95
-				}
96
-			}
97
-		}
98
-
99
-		// Record change
100
-		changes = append(changes, change)
101
-		return nil
102
-	})
103
-	if err != nil && !os.IsNotExist(err) {
104
-		return nil, err
105
-	}
106
-	return changes, nil
107
-}
108
-
109
-func ChangesDirs(newDir, oldDir string) ([]Change, error) {
110
-	var changes []Change
111
-	err := filepath.Walk(newDir, func(newPath string, f os.FileInfo, err error) error {
112
-		if err != nil {
113
-			return err
114
-		}
115
-
116
-		var newStat syscall.Stat_t
117
-		err = syscall.Lstat(newPath, &newStat)
118
-		if err != nil {
119
-			return err
120
-		}
121
-
122
-		// Rebase path
123
-		relPath, err := filepath.Rel(newDir, newPath)
124
-		if err != nil {
125
-			return err
126
-		}
127
-		relPath = filepath.Join("/", relPath)
128
-
129
-		// Skip root
130
-		if relPath == "/" || relPath == "/.docker-id" {
131
-			return nil
132
-		}
133
-
134
-		change := Change{
135
-			Path: relPath,
136
-		}
137
-
138
-		oldPath := filepath.Join(oldDir, relPath)
139
-
140
-		var oldStat = &syscall.Stat_t{}
141
-		err = syscall.Lstat(oldPath, oldStat)
142
-		if err != nil {
143
-			if !os.IsNotExist(err) {
144
-				return err
145
-			}
146
-			oldStat = nil
147
-		}
148
-
149
-		if oldStat == nil {
150
-			change.Kind = ChangeAdd
151
-			changes = append(changes, change)
152
-		} else {
153
-			if oldStat.Ino != newStat.Ino ||
154
-				oldStat.Mode != newStat.Mode ||
155
-				oldStat.Uid != newStat.Uid ||
156
-				oldStat.Gid != newStat.Gid ||
157
-				oldStat.Rdev != newStat.Rdev ||
158
-				oldStat.Size != newStat.Size ||
159
-				oldStat.Blocks != newStat.Blocks ||
160
-				oldStat.Mtim != newStat.Mtim ||
161
-				oldStat.Ctim != newStat.Ctim {
162
-				change.Kind = ChangeModify
163
-				changes = append(changes, change)
164
-			}
165
-		}
166
-
167
-		return nil
168
-	})
169
-	if err != nil {
170
-		return nil, err
171
-	}
172
-	err = filepath.Walk(oldDir, func(oldPath string, f os.FileInfo, err error) error {
173
-		if err != nil {
174
-			return err
175
-		}
176
-
177
-		// Rebase path
178
-		relPath, err := filepath.Rel(oldDir, oldPath)
179
-		if err != nil {
180
-			return err
181
-		}
182
-		relPath = filepath.Join("/", relPath)
183
-
184
-		// Skip root
185
-		if relPath == "/" {
186
-			return nil
187
-		}
188
-
189
-		change := Change{
190
-			Path: relPath,
191
-		}
192
-
193
-		newPath := filepath.Join(newDir, relPath)
194
-
195
-		var newStat = &syscall.Stat_t{}
196
-		err = syscall.Lstat(newPath, newStat)
197
-		if err != nil && os.IsNotExist(err) {
198
-			change.Kind = ChangeDelete
199
-			changes = append(changes, change)
200
-		}
201
-
202
-		return nil
203
-	})
204
-	if err != nil {
205
-		return nil, err
206
-	}
207
-	return changes, nil
208
-}
... ...
@@ -7,7 +7,6 @@ import (
7 7
 	"flag"
8 8
 	"fmt"
9 9
 	"github.com/dotcloud/docker/archive"
10
-	"github.com/dotcloud/docker/graphdriver" // FIXME: graphdriver.Change is a placeholder for archive.Change
11 10
 	"github.com/dotcloud/docker/term"
12 11
 	"github.com/dotcloud/docker/utils"
13 12
 	"github.com/kr/pty"
... ...
@@ -397,7 +396,7 @@ func (container *Container) Inject(file io.Reader, pth string) error {
397 397
 	}
398 398
 
399 399
 	// Return error if path exists
400
-	if _, err := os.Stat(path.Join(container.rwPath(), pth)); err == nil {
400
+	if _, err := os.Stat(path.Join(container.RootfsPath(), pth)); err == nil {
401 401
 		// Since err is nil, the path could be stat'd and it exists
402 402
 		return fmt.Errorf("%s exists", pth)
403 403
 	} else if !os.IsNotExist(err) {
... ...
@@ -1402,7 +1401,7 @@ func (container *Container) Mount() error {
1402 1402
 	return container.runtime.Mount(container)
1403 1403
 }
1404 1404
 
1405
-func (container *Container) Changes() ([]graphdriver.Change, error) {
1405
+func (container *Container) Changes() ([]archive.Change, error) {
1406 1406
 	return container.runtime.Changes(container)
1407 1407
 }
1408 1408
 
... ...
@@ -61,7 +61,7 @@ func (d *Driver) DiffSize(id string) (int64, error) {
61 61
 	return -1, fmt.Errorf("Not implemented")
62 62
 }
63 63
 
64
-func (d *Driver) Changes(id string) ([]graphdriver.Change, error) {
64
+func (d *Driver) Changes(id string) ([]archive.Change, error) {
65 65
 	return nil, fmt.Errorf("Not implemented")
66 66
 }
67 67
 
... ...
@@ -5,12 +5,8 @@ import (
5 5
 	"github.com/dotcloud/docker/archive"
6 6
 )
7 7
 
8
-type InitFunc func(root string) (Driver, error)
9 8
 
10
-// FIXME: this is a temporary placeholder for archive.Change
11
-// (to be merged from master)
12
-type Change interface {
13
-}
9
+type InitFunc func(root string) (Driver, error)
14 10
 
15 11
 type Driver interface {
16 12
 	Create(id, parent string) error
... ...
@@ -20,7 +16,7 @@ type Driver interface {
20 20
 
21 21
 	Diff(id string) (archive.Archive, error)
22 22
 	DiffSize(id string) (bytes int64, err error)
23
-	Changes(id string) ([]Change, error)
23
+	Changes(id string) ([]archive.Change, error)
24 24
 
25 25
 	Cleanup() error
26 26
 }
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"container/list"
6 6
 	"database/sql"
7 7
 	"fmt"
8
+	"github.com/dotcloud/docker/archive"
8 9
 	_ "github.com/dotcloud/docker/devmapper"
9 10
 	"github.com/dotcloud/docker/gograph"
10 11
 	"github.com/dotcloud/docker/graphdriver"
... ...
@@ -728,7 +729,7 @@ func (runtime *Runtime) Unmount(container *Container) error {
728 728
 	return nil
729 729
 }
730 730
 
731
-func (runtime *Runtime) Changes(container *Container) ([]graphdriver.Change, error) {
731
+func (runtime *Runtime) Changes(container *Container) ([]archive.Change, error) {
732 732
 	return runtime.driver.Changes(container.ID)
733 733
 }
734 734
 
... ...
@@ -9,7 +9,6 @@ import (
9 9
 	"github.com/dotcloud/docker/auth"
10 10
 	"github.com/dotcloud/docker/engine"
11 11
 	"github.com/dotcloud/docker/gograph"
12
-	"github.com/dotcloud/docker/graphdriver" // FIXME: graphdriver.Change is a placeholder for archive.Change
13 12
 	"github.com/dotcloud/docker/registry"
14 13
 	"github.com/dotcloud/docker/utils"
15 14
 	"io"
... ...
@@ -449,7 +448,7 @@ func (srv *Server) ContainerTop(name, ps_args string) (*APITop, error) {
449 449
 	return nil, fmt.Errorf("No such container: %s", name)
450 450
 }
451 451
 
452
-func (srv *Server) ContainerChanges(name string) ([]graphdriver.Change, error) {
452
+func (srv *Server) ContainerChanges(name string) ([]archive.Change, error) {
453 453
 	if container := srv.runtime.Get(name); container != nil {
454 454
 		return container.Changes()
455 455
 	}
... ...
@@ -23,6 +23,7 @@ btrfs_reflink(int fd_out, int fd_in)
23 23
 import "C"
24 24
 import (
25 25
 	"fmt"
26
+	"github.com/dotcloud/docker/archive"
26 27
 	"github.com/dotcloud/docker/namesgenerator"
27 28
 	"github.com/dotcloud/docker/utils"
28 29
 	"io"
... ...
@@ -33,6 +34,12 @@ import (
33 33
 	"syscall"
34 34
 )
35 35
 
36
+
37
+type Change struct {
38
+	archive.Change
39
+}
40
+
41
+
36 42
 // Compare two Config struct. Do not compare the "Image" nor "Hostname" fields
37 43
 // If OpenStdin is set, then it differs
38 44
 func CompareConfig(a, b *Config) bool {