| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package cipd | |
| 6 | |
| 7 import ( | |
| 8 "bytes" | |
| 9 "fmt" | |
| 10 "io" | |
| 11 "io/ioutil" | |
| 12 "os" | |
| 13 "path/filepath" | |
| 14 "sort" | |
| 15 "testing" | |
| 16 | |
| 17 . "github.com/smartystreets/goconvey/convey" | |
| 18 ) | |
| 19 | |
| 20 func TestUtilities(t *testing.T) { | |
| 21 Convey("Given a temp directory", t, func() { | |
| 22 tempDir, err := ioutil.TempDir("", "cipd_test") | |
| 23 So(err, ShouldBeNil) | |
| 24 Reset(func() { os.RemoveAll(tempDir) }) | |
| 25 | |
| 26 // Wrappers that accept paths relative to tempDir. | |
| 27 touch := func(rel string) { | |
| 28 abs := filepath.Join(tempDir, filepath.FromSlash(rel)) | |
| 29 err := os.MkdirAll(filepath.Dir(abs), 0777) | |
| 30 So(err, ShouldBeNil) | |
| 31 f, err := os.Create(abs) | |
| 32 So(err, ShouldBeNil) | |
| 33 f.Close() | |
| 34 } | |
| 35 ensureLink := func(symlinkRel string, target string) error { | |
| 36 return ensureSymlink(filepath.Join(tempDir, symlinkRel),
target) | |
| 37 } | |
| 38 readLink := func(symlinkRel string) string { | |
| 39 val, err := os.Readlink(filepath.Join(tempDir, symlinkRe
l)) | |
| 40 So(err, ShouldBeNil) | |
| 41 return val | |
| 42 } | |
| 43 | |
| 44 Convey("ensureSymlink creates new symlink", func() { | |
| 45 So(ensureLink("symlink", "target"), ShouldBeNil) | |
| 46 So(readLink("symlink"), ShouldEqual, "target") | |
| 47 }) | |
| 48 | |
| 49 Convey("ensureSymlink builds full path", func() { | |
| 50 So(ensureLink(filepath.Join("a", "b", "c"), "target"), S
houldBeNil) | |
| 51 So(readLink(filepath.Join("a", "b", "c")), ShouldEqual,
"target") | |
| 52 }) | |
| 53 | |
| 54 Convey("ensureSymlink replaces existing one", func() { | |
| 55 So(ensureLink("symlink", "target"), ShouldBeNil) | |
| 56 So(ensureLink("symlink", "another"), ShouldBeNil) | |
| 57 So(readLink("symlink"), ShouldEqual, "another") | |
| 58 }) | |
| 59 | |
| 60 Convey("scanPackageDir works with empty dir", func() { | |
| 61 err := os.Mkdir(filepath.Join(tempDir, "dir"), 0777) | |
| 62 So(err, ShouldBeNil) | |
| 63 files := makeStringSet() | |
| 64 err = scanPackageDir(filepath.Join(tempDir, "dir"), file
s) | |
| 65 So(err, ShouldBeNil) | |
| 66 So(len(files), ShouldEqual, 0) | |
| 67 }) | |
| 68 | |
| 69 Convey("scanPackageDir works", func() { | |
| 70 touch("unrelated/1") | |
| 71 touch("dir/a/1") | |
| 72 touch("dir/a/2") | |
| 73 touch("dir/b/1") | |
| 74 touch("dir/.cipdpkg/abc") | |
| 75 touch("dir/.cipd/abc") | |
| 76 ensureLink("dir/a/sym_link", "target") | |
| 77 files := makeStringSet() | |
| 78 err := scanPackageDir(filepath.Join(tempDir, "dir"), fil
es) | |
| 79 So(err, ShouldBeNil) | |
| 80 names := sort.StringSlice{} | |
| 81 for n := range files { | |
| 82 names = append(names, filepath.ToSlash(n)) | |
| 83 } | |
| 84 names.Sort() | |
| 85 So(names, ShouldResemble, sort.StringSlice{ | |
| 86 "a/1", | |
| 87 "a/2", | |
| 88 "a/sym_link", | |
| 89 "b/1", | |
| 90 }) | |
| 91 }) | |
| 92 | |
| 93 Convey("ensureDirectoryGone works with missing dir", func() { | |
| 94 So(ensureDirectoryGone(filepath.Join(tempDir, "missing")
), ShouldBeNil) | |
| 95 }) | |
| 96 | |
| 97 Convey("ensureDirectoryGone works", func() { | |
| 98 touch("dir/a/1") | |
| 99 touch("dir/a/2") | |
| 100 touch("dir/b/1") | |
| 101 So(ensureDirectoryGone(filepath.Join(tempDir, "dir")), S
houldBeNil) | |
| 102 _, err := os.Stat(filepath.Join(tempDir, "dir")) | |
| 103 So(os.IsNotExist(err), ShouldBeTrue) | |
| 104 }) | |
| 105 | |
| 106 Convey("ensureFileGone works", func() { | |
| 107 touch("abc") | |
| 108 So(ensureFileGone(filepath.Join(tempDir, "abc")), Should
BeNil) | |
| 109 _, err := os.Stat(filepath.Join(tempDir, "abc")) | |
| 110 So(os.IsNotExist(err), ShouldBeTrue) | |
| 111 }) | |
| 112 | |
| 113 Convey("ensureFileGone works with missing file", func() { | |
| 114 So(ensureFileGone(filepath.Join(tempDir, "abc")), Should
BeNil) | |
| 115 }) | |
| 116 | |
| 117 Convey("ensureFileGone works with symlink", func() { | |
| 118 ensureLink("abc", "target") | |
| 119 So(ensureFileGone(filepath.Join(tempDir, "abc")), Should
BeNil) | |
| 120 _, err := os.Stat(filepath.Join(tempDir, "abc")) | |
| 121 So(os.IsNotExist(err), ShouldBeTrue) | |
| 122 }) | |
| 123 }) | |
| 124 } | |
| 125 | |
| 126 func TestDeployInstance(t *testing.T) { | |
| 127 Convey("Given a temp directory", t, func() { | |
| 128 tempDir, err := ioutil.TempDir("", "cipd_test") | |
| 129 So(err, ShouldBeNil) | |
| 130 Reset(func() { os.RemoveAll(tempDir) }) | |
| 131 | |
| 132 Convey("DeployInstance new empty package instance", func() { | |
| 133 inst := makeTestInstance("test/package", nil) | |
| 134 info, err := DeployInstance(tempDir, inst) | |
| 135 So(err, ShouldBeNil) | |
| 136 So(info, ShouldResemble, PackageState{ | |
| 137 PackageName: "test/package", | |
| 138 InstanceID: inst.InstanceID(), | |
| 139 }) | |
| 140 So(scanDir(tempDir), ShouldResemble, []string{ | |
| 141 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/.cipdpkg/manifest.json", | |
| 142 ".cipd/pkgs/test_package_B6R4ErK5ko/_current:012
3456789abcdef00000123456789abcdef0000", | |
| 143 }) | |
| 144 }) | |
| 145 | |
| 146 Convey("DeployInstance new non-empty package instance", func() { | |
| 147 inst := makeTestInstance("test/package", []File{ | |
| 148 makeTestFile("some/file/path", "data a", false), | |
| 149 makeTestFile("some/executable", "data b", true), | |
| 150 makeTestSymlink("some/symlink", "executable"), | |
| 151 }) | |
| 152 _, err := DeployInstance(tempDir, inst) | |
| 153 So(err, ShouldBeNil) | |
| 154 So(scanDir(tempDir), ShouldResemble, []string{ | |
| 155 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/.cipdpkg/manifest.json", | |
| 156 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/some/executable*", | |
| 157 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/some/file/path", | |
| 158 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/some/symlink:executable", | |
| 159 ".cipd/pkgs/test_package_B6R4ErK5ko/_current:012
3456789abcdef00000123456789abcdef0000", | |
| 160 "some/executable:../.cipd/pkgs/test_package_B6R4
ErK5ko/_current/some/executable", | |
| 161 "some/file/path:../../.cipd/pkgs/test_package_B6
R4ErK5ko/_current/some/file/path", | |
| 162 "some/symlink:../.cipd/pkgs/test_package_B6R4ErK
5ko/_current/some/symlink", | |
| 163 }) | |
| 164 // Ensure symlinks are actually traversable. | |
| 165 body, err := ioutil.ReadFile(filepath.Join(tempDir, "som
e", "file", "path")) | |
| 166 So(err, ShouldBeNil) | |
| 167 So(string(body), ShouldEqual, "data a") | |
| 168 // Symlink to symlink is traversable too. | |
| 169 body, err = ioutil.ReadFile(filepath.Join(tempDir, "some
", "symlink")) | |
| 170 So(err, ShouldBeNil) | |
| 171 So(string(body), ShouldEqual, "data b") | |
| 172 }) | |
| 173 | |
| 174 Convey("Redeploy same package instance", func() { | |
| 175 inst := makeTestInstance("test/package", []File{ | |
| 176 makeTestFile("some/file/path", "data a", false), | |
| 177 makeTestFile("some/executable", "data b", true), | |
| 178 makeTestSymlink("some/symlink", "executable"), | |
| 179 }) | |
| 180 _, err := DeployInstance(tempDir, inst) | |
| 181 So(err, ShouldBeNil) | |
| 182 _, err = DeployInstance(tempDir, inst) | |
| 183 So(err, ShouldBeNil) | |
| 184 So(scanDir(tempDir), ShouldResemble, []string{ | |
| 185 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/.cipdpkg/manifest.json", | |
| 186 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/some/executable*", | |
| 187 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/some/file/path", | |
| 188 ".cipd/pkgs/test_package_B6R4ErK5ko/0123456789ab
cdef00000123456789abcdef0000/some/symlink:executable", | |
| 189 ".cipd/pkgs/test_package_B6R4ErK5ko/_current:012
3456789abcdef00000123456789abcdef0000", | |
| 190 "some/executable:../.cipd/pkgs/test_package_B6R4
ErK5ko/_current/some/executable", | |
| 191 "some/file/path:../../.cipd/pkgs/test_package_B6
R4ErK5ko/_current/some/file/path", | |
| 192 "some/symlink:../.cipd/pkgs/test_package_B6R4ErK
5ko/_current/some/symlink", | |
| 193 }) | |
| 194 }) | |
| 195 | |
| 196 Convey("DeployInstance package update", func() { | |
| 197 oldPkg := makeTestInstance("test/package", []File{ | |
| 198 makeTestFile("some/file/path", "data a old", fal
se), | |
| 199 makeTestFile("some/executable", "data b old", tr
ue), | |
| 200 makeTestFile("old only", "data c old", true), | |
| 201 makeTestFile("mode change 1", "data d", true), | |
| 202 makeTestFile("mode change 2", "data e", false), | |
| 203 makeTestSymlink("symlink unchanged", "target"), | |
| 204 makeTestSymlink("symlink changed", "old target")
, | |
| 205 makeTestSymlink("symlink removed", "target"), | |
| 206 }) | |
| 207 oldPkg.instanceID = "00000000000000000000000000000000000
00000" | |
| 208 | |
| 209 newPkg := makeTestInstance("test/package", []File{ | |
| 210 makeTestFile("some/file/path", "data a new", fal
se), | |
| 211 makeTestFile("some/executable", "data b new", tr
ue), | |
| 212 makeTestFile("mode change 1", "data d", false), | |
| 213 makeTestFile("mode change 2", "data d", true), | |
| 214 makeTestSymlink("symlink unchanged", "target"), | |
| 215 makeTestSymlink("symlink changed", "new target")
, | |
| 216 }) | |
| 217 newPkg.instanceID = "11111111111111111111111111111111111
11111" | |
| 218 | |
| 219 _, err := DeployInstance(tempDir, oldPkg) | |
| 220 So(err, ShouldBeNil) | |
| 221 _, err = DeployInstance(tempDir, newPkg) | |
| 222 So(err, ShouldBeNil) | |
| 223 | |
| 224 So(scanDir(tempDir), ShouldResemble, []string{ | |
| 225 ".cipd/pkgs/test_package_B6R4ErK5ko/111111111111
1111111111111111111111111111/.cipdpkg/manifest.json", | |
| 226 ".cipd/pkgs/test_package_B6R4ErK5ko/111111111111
1111111111111111111111111111/mode change 1", | |
| 227 ".cipd/pkgs/test_package_B6R4ErK5ko/111111111111
1111111111111111111111111111/mode change 2*", | |
| 228 ".cipd/pkgs/test_package_B6R4ErK5ko/111111111111
1111111111111111111111111111/some/executable*", | |
| 229 ".cipd/pkgs/test_package_B6R4ErK5ko/111111111111
1111111111111111111111111111/some/file/path", | |
| 230 ".cipd/pkgs/test_package_B6R4ErK5ko/111111111111
1111111111111111111111111111/symlink changed:new target", | |
| 231 ".cipd/pkgs/test_package_B6R4ErK5ko/111111111111
1111111111111111111111111111/symlink unchanged:target", | |
| 232 ".cipd/pkgs/test_package_B6R4ErK5ko/_current:111
1111111111111111111111111111111111111", | |
| 233 "mode change 1:.cipd/pkgs/test_package_B6R4ErK5k
o/_current/mode change 1", | |
| 234 "mode change 2:.cipd/pkgs/test_package_B6R4ErK5k
o/_current/mode change 2", | |
| 235 "some/executable:../.cipd/pkgs/test_package_B6R4
ErK5ko/_current/some/executable", | |
| 236 "some/file/path:../../.cipd/pkgs/test_package_B6
R4ErK5ko/_current/some/file/path", | |
| 237 "symlink changed:.cipd/pkgs/test_package_B6R4ErK
5ko/_current/symlink changed", | |
| 238 "symlink unchanged:.cipd/pkgs/test_package_B6R4E
rK5ko/_current/symlink unchanged", | |
| 239 }) | |
| 240 }) | |
| 241 | |
| 242 Convey("DeployInstance two different packages", func() { | |
| 243 pkg1 := makeTestInstance("test/package", []File{ | |
| 244 makeTestFile("some/file/path", "data a old", fal
se), | |
| 245 makeTestFile("some/executable", "data b old", tr
ue), | |
| 246 makeTestFile("pkg1 file", "data c", false), | |
| 247 }) | |
| 248 pkg1.instanceID = "0000000000000000000000000000000000000
000" | |
| 249 | |
| 250 // Nesting in package names is allowed. | |
| 251 pkg2 := makeTestInstance("test/package/another", []File{ | |
| 252 makeTestFile("some/file/path", "data a new", fal
se), | |
| 253 makeTestFile("some/executable", "data b new", tr
ue), | |
| 254 makeTestFile("pkg2 file", "data d", false), | |
| 255 }) | |
| 256 pkg2.instanceID = "1111111111111111111111111111111111111
111" | |
| 257 | |
| 258 _, err := DeployInstance(tempDir, pkg1) | |
| 259 So(err, ShouldBeNil) | |
| 260 _, err = DeployInstance(tempDir, pkg2) | |
| 261 So(err, ShouldBeNil) | |
| 262 | |
| 263 // TODO: Conflicting symlinks point to last installed pa
ckage, it is not | |
| 264 // very deterministic. | |
| 265 So(scanDir(tempDir), ShouldResemble, []string{ | |
| 266 ".cipd/pkgs/package_another_4HL4H61fGm/111111111
1111111111111111111111111111111/.cipdpkg/manifest.json", | |
| 267 ".cipd/pkgs/package_another_4HL4H61fGm/111111111
1111111111111111111111111111111/pkg2 file", | |
| 268 ".cipd/pkgs/package_another_4HL4H61fGm/111111111
1111111111111111111111111111111/some/executable*", | |
| 269 ".cipd/pkgs/package_another_4HL4H61fGm/111111111
1111111111111111111111111111111/some/file/path", | |
| 270 ".cipd/pkgs/package_another_4HL4H61fGm/_current:
1111111111111111111111111111111111111111", | |
| 271 ".cipd/pkgs/test_package_B6R4ErK5ko/000000000000
0000000000000000000000000000/.cipdpkg/manifest.json", | |
| 272 ".cipd/pkgs/test_package_B6R4ErK5ko/000000000000
0000000000000000000000000000/pkg1 file", | |
| 273 ".cipd/pkgs/test_package_B6R4ErK5ko/000000000000
0000000000000000000000000000/some/executable*", | |
| 274 ".cipd/pkgs/test_package_B6R4ErK5ko/000000000000
0000000000000000000000000000/some/file/path", | |
| 275 ".cipd/pkgs/test_package_B6R4ErK5ko/_current:000
0000000000000000000000000000000000000", | |
| 276 "pkg1 file:.cipd/pkgs/test_package_B6R4ErK5ko/_c
urrent/pkg1 file", | |
| 277 "pkg2 file:.cipd/pkgs/package_another_4HL4H61fGm
/_current/pkg2 file", | |
| 278 "some/executable:../.cipd/pkgs/package_another_4
HL4H61fGm/_current/some/executable", | |
| 279 "some/file/path:../../.cipd/pkgs/package_another
_4HL4H61fGm/_current/some/file/path", | |
| 280 }) | |
| 281 }) | |
| 282 | |
| 283 Convey("Try to deploy package instance with bad package name", f
unc() { | |
| 284 _, err := DeployInstance(tempDir, makeTestInstance("../t
est/package", nil)) | |
| 285 So(err, ShouldNotBeNil) | |
| 286 }) | |
| 287 | |
| 288 Convey("Try to deploy package instance with bad instance ID", fu
nc() { | |
| 289 inst := makeTestInstance("test/package", nil) | |
| 290 inst.instanceID = "../000000000" | |
| 291 _, err := DeployInstance(tempDir, inst) | |
| 292 So(err, ShouldNotBeNil) | |
| 293 }) | |
| 294 }) | |
| 295 } | |
| 296 | |
| 297 func TestFindDeployed(t *testing.T) { | |
| 298 Convey("Given a temp directory", t, func() { | |
| 299 tempDir, err := ioutil.TempDir("", "cipd_test") | |
| 300 So(err, ShouldBeNil) | |
| 301 Reset(func() { os.RemoveAll(tempDir) }) | |
| 302 | |
| 303 Convey("FindDeployed works with empty dir", func() { | |
| 304 out, err := FindDeployed(tempDir) | |
| 305 So(err, ShouldBeNil) | |
| 306 So(out, ShouldBeNil) | |
| 307 }) | |
| 308 | |
| 309 Convey("FindDeployed works", func() { | |
| 310 // Deploy a bunch of stuff. | |
| 311 _, err := DeployInstance(tempDir, makeTestInstance("test
/pkg/123", nil)) | |
| 312 So(err, ShouldBeNil) | |
| 313 _, err = DeployInstance(tempDir, makeTestInstance("test/
pkg/456", nil)) | |
| 314 So(err, ShouldBeNil) | |
| 315 _, err = DeployInstance(tempDir, makeTestInstance("test/
pkg", nil)) | |
| 316 So(err, ShouldBeNil) | |
| 317 _, err = DeployInstance(tempDir, makeTestInstance("test"
, nil)) | |
| 318 So(err, ShouldBeNil) | |
| 319 | |
| 320 // Verify it is discoverable. | |
| 321 out, err := FindDeployed(tempDir) | |
| 322 So(err, ShouldBeNil) | |
| 323 So(out, ShouldResemble, []PackageState{ | |
| 324 PackageState{ | |
| 325 PackageName: "test", | |
| 326 InstanceID: "0123456789abcdef0000012345
6789abcdef0000", | |
| 327 }, | |
| 328 PackageState{ | |
| 329 PackageName: "test/pkg", | |
| 330 InstanceID: "0123456789abcdef0000012345
6789abcdef0000", | |
| 331 }, | |
| 332 PackageState{ | |
| 333 PackageName: "test/pkg/123", | |
| 334 InstanceID: "0123456789abcdef0000012345
6789abcdef0000", | |
| 335 }, | |
| 336 PackageState{ | |
| 337 PackageName: "test/pkg/456", | |
| 338 InstanceID: "0123456789abcdef0000012345
6789abcdef0000", | |
| 339 }, | |
| 340 }) | |
| 341 }) | |
| 342 }) | |
| 343 } | |
| 344 | |
| 345 func TestRemoveDeployed(t *testing.T) { | |
| 346 Convey("Given a temp directory", t, func() { | |
| 347 tempDir, err := ioutil.TempDir("", "cipd_test") | |
| 348 So(err, ShouldBeNil) | |
| 349 Reset(func() { os.RemoveAll(tempDir) }) | |
| 350 | |
| 351 Convey("RemoveDeployed works with missing package", func() { | |
| 352 err := RemoveDeployed(tempDir, "package/path") | |
| 353 So(err, ShouldBeNil) | |
| 354 }) | |
| 355 | |
| 356 Convey("RemoveDeployed works", func() { | |
| 357 // Deploy some instance (to keep it). | |
| 358 inst := makeTestInstance("test/package/123", []File{ | |
| 359 makeTestFile("some/file/path1", "data a", false)
, | |
| 360 makeTestFile("some/executable1", "data b", true)
, | |
| 361 }) | |
| 362 _, err := DeployInstance(tempDir, inst) | |
| 363 So(err, ShouldBeNil) | |
| 364 | |
| 365 // Deploy another instance (to remove it). | |
| 366 inst = makeTestInstance("test/package", []File{ | |
| 367 makeTestFile("some/file/path2", "data a", false)
, | |
| 368 makeTestFile("some/executable2", "data b", true)
, | |
| 369 makeTestSymlink("some/symlink", "executable"), | |
| 370 }) | |
| 371 _, err = DeployInstance(tempDir, inst) | |
| 372 So(err, ShouldBeNil) | |
| 373 | |
| 374 // Now remove the second package. | |
| 375 err = RemoveDeployed(tempDir, "test/package") | |
| 376 So(err, ShouldBeNil) | |
| 377 | |
| 378 // Verify the final state (only first package should sur
vive). | |
| 379 So(scanDir(tempDir), ShouldResemble, []string{ | |
| 380 ".cipd/pkgs/package_123_Wnok5l4iFr/0123456789abc
def00000123456789abcdef0000/.cipdpkg/manifest.json", | |
| 381 ".cipd/pkgs/package_123_Wnok5l4iFr/0123456789abc
def00000123456789abcdef0000/some/executable1*", | |
| 382 ".cipd/pkgs/package_123_Wnok5l4iFr/0123456789abc
def00000123456789abcdef0000/some/file/path1", | |
| 383 ".cipd/pkgs/package_123_Wnok5l4iFr/_current:0123
456789abcdef00000123456789abcdef0000", | |
| 384 "some/executable1:../.cipd/pkgs/package_123_Wnok
5l4iFr/_current/some/executable1", | |
| 385 "some/file/path1:../../.cipd/pkgs/package_123_Wn
ok5l4iFr/_current/some/file/path1", | |
| 386 }) | |
| 387 }) | |
| 388 }) | |
| 389 } | |
| 390 | |
| 391 //////////////////////////////////////////////////////////////////////////////// | |
| 392 | |
| 393 type testPackageInstance struct { | |
| 394 packageName string | |
| 395 instanceID string | |
| 396 files []File | |
| 397 } | |
| 398 | |
| 399 // makeTestInstance returns PackageInstance implementation with mocked guts. | |
| 400 func makeTestInstance(name string, files []File) *testPackageInstance { | |
| 401 // Generate and append manifest file. | |
| 402 out := bytes.Buffer{} | |
| 403 err := writeManifest(&Manifest{ | |
| 404 FormatVersion: manifestFormatVersion, | |
| 405 PackageName: name, | |
| 406 }, &out) | |
| 407 if err != nil { | |
| 408 panic("Failed to write a manifest") | |
| 409 } | |
| 410 files = append(files, makeTestFile(manifestName, string(out.Bytes()), fa
lse)) | |
| 411 return &testPackageInstance{ | |
| 412 packageName: name, | |
| 413 instanceID: "0123456789abcdef00000123456789abcdef0000", | |
| 414 files: files, | |
| 415 } | |
| 416 } | |
| 417 | |
| 418 func (f *testPackageInstance) Close() error { return nil } | |
| 419 func (f *testPackageInstance) PackageName() string { return f.packageName
} | |
| 420 func (f *testPackageInstance) InstanceID() string { return f.instanceID } | |
| 421 func (f *testPackageInstance) Files() []File { return f.files } | |
| 422 func (f *testPackageInstance) DataReader() io.ReadSeeker { panic("Not implemente
d") } | |
| 423 | |
| 424 //////////////////////////////////////////////////////////////////////////////// | |
| 425 | |
| 426 // scanDir returns list of files (regular and symlinks) it finds in a directory. | |
| 427 // Symlinks are returned as "path:target". Regular executable files are suffixed | |
| 428 // with '*'. All paths are relative to the scanned directory and slash | |
| 429 // separated. Symlink targets are slash separated too, but otherwise not | |
| 430 // modified. Does not look inside symlinked directories. | |
| 431 func scanDir(root string) (out []string) { | |
| 432 err := filepath.Walk(root, func(path string, info os.FileInfo, err error
) error { | |
| 433 if err != nil { | |
| 434 return err | |
| 435 } | |
| 436 rel, err := filepath.Rel(root, path) | |
| 437 if err != nil { | |
| 438 return err | |
| 439 } | |
| 440 if info.Mode().IsDir() { | |
| 441 return nil | |
| 442 } | |
| 443 | |
| 444 rel = filepath.ToSlash(rel) | |
| 445 target, err := os.Readlink(path) | |
| 446 var item string | |
| 447 if err == nil { | |
| 448 item = fmt.Sprintf("%s:%s", rel, filepath.ToSlash(target
)) | |
| 449 } else { | |
| 450 if info.Mode().IsRegular() { | |
| 451 item = rel | |
| 452 } else { | |
| 453 item = fmt.Sprintf("%s:??????", rel) | |
| 454 } | |
| 455 } | |
| 456 | |
| 457 suffix := "" | |
| 458 if info.Mode().IsRegular() && (info.Mode().Perm()&0100) != 0 { | |
| 459 suffix = "*" | |
| 460 } | |
| 461 | |
| 462 out = append(out, item+suffix) | |
| 463 return nil | |
| 464 }) | |
| 465 if err != nil { | |
| 466 panic("Failed to walk a directory") | |
| 467 } | |
| 468 return | |
| 469 } | |
| OLD | NEW |