| Index: go/src/infra/tools/cipd/local/files.go
|
| diff --git a/go/src/infra/tools/cipd/local/files.go b/go/src/infra/tools/cipd/local/files.go
|
| index 5eee65937c37a250c02ce21fcfa56f6134ba1b54..27f429e3b44f82e5b5ae4d7a9954d99960696e47 100644
|
| --- a/go/src/infra/tools/cipd/local/files.go
|
| +++ b/go/src/infra/tools/cipd/local/files.go
|
| @@ -234,6 +234,8 @@ func isSubpath(path, root string) bool {
|
| type fileSystemDestination struct {
|
| // Destination directory.
|
| dir string
|
| + // FileSystem implementation to use.
|
| + fs FileSystem
|
| // Root temporary directory.
|
| tempDir string
|
| // Where to extract all temp files, subdirectory of tempDir.
|
| @@ -243,39 +245,44 @@ type fileSystemDestination struct {
|
| }
|
|
|
| // NewFileSystemDestination returns a destination in the file system (directory)
|
| -// to extract a package to.
|
| -func NewFileSystemDestination(dir string) Destination {
|
| +// to extract a package to. Will use a provided FileSystem object to operate on
|
| +// files if given, otherwise use a default one. If FileSystem is provided, dir
|
| +// must be in a subdirectory of the given FileSystem root.
|
| +func NewFileSystemDestination(dir string, fs FileSystem) Destination {
|
| + if fs == nil {
|
| + fs = NewFileSystem(filepath.Dir(dir), nil)
|
| + }
|
| return &fileSystemDestination{
|
| dir: dir,
|
| + fs: fs,
|
| openFiles: map[string]*os.File{},
|
| }
|
| }
|
|
|
| -func (d *fileSystemDestination) Begin() (err error) {
|
| +func (d *fileSystemDestination) Begin() error {
|
| if d.tempDir != "" {
|
| return fmt.Errorf("Destination is already open")
|
| }
|
|
|
| - // Ensure parent directory of destination directory exists.
|
| - d.dir, err = filepath.Abs(filepath.Clean(d.dir))
|
| - if err != nil {
|
| + // Ensure a parent directory of the destination directory exists.
|
| + var err error
|
| + if d.dir, err = d.fs.ToAbsPath(d.dir); err != nil {
|
| return err
|
| }
|
| - err = os.MkdirAll(filepath.Dir(d.dir), 0777)
|
| - if err != nil {
|
| + if _, err := d.fs.EnsureDirectory(filepath.Dir(d.dir)); err != nil {
|
| return err
|
| }
|
|
|
| // Called in case something below fails.
|
| cleanup := func() {
|
| if d.tempDir != "" {
|
| - os.RemoveAll(d.tempDir)
|
| + d.fs.EnsureDirectoryGone(d.tempDir)
|
| }
|
| d.tempDir = ""
|
| d.outDir = ""
|
| }
|
|
|
| - // Create root temp dir, on the same level as destination directory.
|
| + // Create root temp dir, on the same level as the destination directory.
|
| d.tempDir, err = ioutil.TempDir(filepath.Dir(d.dir), filepath.Base(d.dir)+"_")
|
| if err != nil {
|
| cleanup()
|
| @@ -283,8 +290,7 @@ func (d *fileSystemDestination) Begin() (err error) {
|
| }
|
|
|
| // Create a staging output directory where everything will be extracted.
|
| - d.outDir = filepath.Join(d.tempDir, "out")
|
| - err = os.MkdirAll(d.outDir, 0777)
|
| + d.outDir, err = d.fs.EnsureDirectory(filepath.Join(d.tempDir, "out"))
|
| if err != nil {
|
| cleanup()
|
| return err
|
| @@ -294,8 +300,7 @@ func (d *fileSystemDestination) Begin() (err error) {
|
| }
|
|
|
| func (d *fileSystemDestination) CreateFile(name string, executable bool) (io.WriteCloser, error) {
|
| - _, ok := d.openFiles[name]
|
| - if ok {
|
| + if _, ok := d.openFiles[name]; ok {
|
| return nil, fmt.Errorf("File %s is already open", name)
|
| }
|
|
|
| @@ -341,7 +346,7 @@ func (d *fileSystemDestination) CreateSymlink(name string, target string) error
|
| }
|
| }
|
|
|
| - return os.Symlink(target, path)
|
| + return d.fs.EnsureSymlink(path, target)
|
| }
|
|
|
| func (d *fileSystemDestination) End(success bool) error {
|
| @@ -354,29 +359,15 @@ func (d *fileSystemDestination) End(success bool) error {
|
|
|
| // Clean up temp dir and the state no matter what.
|
| defer func() {
|
| - os.RemoveAll(d.tempDir)
|
| + d.fs.EnsureDirectoryGone(d.tempDir)
|
| d.tempDir = ""
|
| d.outDir = ""
|
| }()
|
|
|
| if success {
|
| - // Move existing directory away, if it is there.
|
| - old := filepath.Join(d.tempDir, "old")
|
| - if os.Rename(d.dir, old) != nil {
|
| - old = ""
|
| - }
|
| -
|
| - // Move new directory in place.
|
| - err := os.Rename(d.outDir, d.dir)
|
| - if err != nil {
|
| - // Try to return the original directory back...
|
| - if old != "" {
|
| - os.Rename(old, d.dir)
|
| - }
|
| - return err
|
| - }
|
| + return d.fs.Replace(d.outDir, d.dir)
|
| }
|
| -
|
| + // Let the defer to clean the garbage in tempDir.
|
| return nil
|
| }
|
|
|
| @@ -392,8 +383,7 @@ func (d *fileSystemDestination) prepareFilePath(name string) (string, error) {
|
| if !isSubpath(path, d.outDir) {
|
| return "", fmt.Errorf("Invalid relative file name: %s", name)
|
| }
|
| - err := os.MkdirAll(filepath.Dir(path), 0777)
|
| - if err != nil {
|
| + if _, err := d.fs.EnsureDirectory(filepath.Dir(path)); err != nil {
|
| return "", err
|
| }
|
| return path, nil
|
|
|