Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: go/src/infra/tools/cipd/local/fs.go

Issue 1258673004: cipd: Make it work on Windows. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package local 5 package local
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "io/ioutil"
9 "os" 10 "os"
10 "path/filepath" 11 "path/filepath"
11 "strings" 12 "strings"
12 "sync" 13 "sync"
13 "time" 14 "time"
14 15
15 "github.com/luci/luci-go/common/logging" 16 "github.com/luci/luci-go/common/logging"
16 ) 17 )
17 18
18 // FileSystem is a high-level interface for operations that touch single file 19 // FileSystem is a high-level interface for operations that touch single file
(...skipping 17 matching lines...) Expand all
36 37
37 // EnsureDirectory creates a directory at given native path if it doesn' t 38 // EnsureDirectory creates a directory at given native path if it doesn' t
38 // exist yet. It takes an absolute path or a path relative to the curren t 39 // exist yet. It takes an absolute path or a path relative to the curren t
39 // working directory and always returns absolute path. 40 // working directory and always returns absolute path.
40 EnsureDirectory(path string) (string, error) 41 EnsureDirectory(path string) (string, error)
41 42
42 // EnsureSymlink creates a symlink pointing to a target. It will create full 43 // EnsureSymlink creates a symlink pointing to a target. It will create full
43 // directory path to the symlink if necessary. 44 // directory path to the symlink if necessary.
44 EnsureSymlink(path string, target string) error 45 EnsureSymlink(path string, target string) error
45 46
47 // EnsureFile creates a file with given content. If will create full dir ectory
48 // path to the file if necessary.
49 EnsureFile(path string, body []byte, perm os.FileMode) error
50
46 // EnsureFileGone removes a file, logging the errors (if any). Missing f ile is 51 // EnsureFileGone removes a file, logging the errors (if any). Missing f ile is
47 // not an error. 52 // not an error.
48 EnsureFileGone(path string) error 53 EnsureFileGone(path string) error
49 54
50 // EnsureDirectoryGone recursively removes a directory. 55 // EnsureDirectoryGone recursively removes a directory.
51 EnsureDirectoryGone(path string) error 56 EnsureDirectoryGone(path string) error
52 57
53 // Renames oldpath to newpath. If newpath already exists (be it a file o r a 58 // Renames oldpath to newpath. If newpath already exists (be it a file o r a
54 // directory), removes it first. If oldpath is a symlink, it's moved as is 59 // directory), removes it first. If oldpath is a symlink, it's moved as is
55 // (e.g. as a symlink). 60 // (e.g. as a symlink).
(...skipping 15 matching lines...) Expand all
71 return &fsImpl{abs, logger} 76 return &fsImpl{abs, logger}
72 } 77 }
73 78
74 // fsImplErr implements FileSystem by returning given error from all methods. 79 // fsImplErr implements FileSystem by returning given error from all methods.
75 type fsImplErr struct { 80 type fsImplErr struct {
76 err error 81 err error
77 } 82 }
78 83
79 // Root returns absolute path to a directory FileSystem operates in. All FS 84 // Root returns absolute path to a directory FileSystem operates in. All FS
80 // actions are restricted to this directory. 85 // actions are restricted to this directory.
81 func (f *fsImplErr) Root() string { return "" } 86 func (f *fsImplErr) Root() string { return "" }
82 func (f *fsImplErr) CwdRelToAbs(path string) (string, error) { return "", f.err } 87 func (f *fsImplErr) CwdRelToAbs(path string) (string, error) { return "", f.err }
83 func (f *fsImplErr) RootRelToAbs(path string) (string, error) { return "", f.err } 88 func (f *fsImplErr) RootRelToAbs(path string) (string, error) { return "", f.err }
84 func (f *fsImplErr) EnsureDirectory(path string) (string, error) { return "", f.err } 89 func (f *fsImplErr) EnsureDirectory(path string) (string, error) { return "", f.err }
85 func (f *fsImplErr) EnsureSymlink(path string, target string) error { return f.e rr } 90 func (f *fsImplErr) EnsureSymlink(path string, target string) error { return f.err }
86 func (f *fsImplErr) EnsureFileGone(path string) error { return f.e rr } 91 func (f *fsImplErr) EnsureFile(path string, body []byte, perm os.FileMode) error { return f.err }
87 func (f *fsImplErr) EnsureDirectoryGone(path string) error { return f.e rr } 92 func (f *fsImplErr) EnsureFileGone(path string) error { return f.err }
88 func (f *fsImplErr) Replace(oldpath, newpath string) error { return f.e rr } 93 func (f *fsImplErr) EnsureDirectoryGone(path string) error { return f.err }
94 func (f *fsImplErr) Replace(oldpath, newpath string) error { return f.err }
89 95
90 /// Implementation. 96 /// Implementation.
91 97
92 type fsImpl struct { 98 type fsImpl struct {
93 root string 99 root string
94 logger logging.Logger 100 logger logging.Logger
95 } 101 }
96 102
97 func (f *fsImpl) Root() string { 103 func (f *fsImpl) Root() string {
98 return f.root 104 return f.root
(...skipping 24 matching lines...) Expand all
123 129
124 func (f *fsImpl) EnsureDirectory(path string) (string, error) { 130 func (f *fsImpl) EnsureDirectory(path string) (string, error) {
125 path, err := f.CwdRelToAbs(path) 131 path, err := f.CwdRelToAbs(path)
126 if err != nil { 132 if err != nil {
127 return "", err 133 return "", err
128 } 134 }
129 // MkdirAll returns nil if path already exists. 135 // MkdirAll returns nil if path already exists.
130 if err = os.MkdirAll(path, 0777); err != nil { 136 if err = os.MkdirAll(path, 0777); err != nil {
131 return "", err 137 return "", err
132 } 138 }
139 // TODO(vadimsh): Do not fail if path already exists and is a regular fi le?
nodir 2015/07/29 20:43:47 probably not, because this func must ensure that a
Vadim Sh. 2015/07/29 21:04:28 I mean if a/b/c exists and is a regular file, Ensu
nodir 2015/07/29 21:08:59 Acknowledged.
133 return path, nil 140 return path, nil
134 } 141 }
135 142
143 func (f *fsImpl) EnsureFile(path string, body []byte, perm os.FileMode) error {
144 path, err := f.CwdRelToAbs(path)
145 if err != nil {
146 return err
147 }
148 if _, err := f.EnsureDirectory(filepath.Dir(path)); err != nil {
149 return err
150 }
151
152 // Create a temp file with new content.
153 temp := fmt.Sprintf("%s_%s", path, pseudoRand())
154 if err := ioutil.WriteFile(temp, body, perm); err != nil {
155 return err
156 }
157
158 // Replace the current file (if there's one) with a new one. Use nuclear
159 // version (f.Replace) instead of simple atomicReplace to handle various edge
160 // cases handled by the nuclear version (e.g replacing a non-empty direc tory).
161 if err := f.Replace(temp, path); err != nil {
162 if err2 := os.Remove(temp); err2 != nil && !os.IsNotExist(err2) {
163 f.logger.Warningf("fs: failed to remove %s - %s", temp, err2)
164 }
165 return err
166 }
167
168 return nil
169 }
170
136 func (f *fsImpl) EnsureSymlink(path string, target string) error { 171 func (f *fsImpl) EnsureSymlink(path string, target string) error {
137 path, err := f.CwdRelToAbs(path) 172 path, err := f.CwdRelToAbs(path)
138 if err != nil { 173 if err != nil {
139 return err 174 return err
140 } 175 }
141 if existing, _ := os.Readlink(path); existing == target { 176 if existing, _ := os.Readlink(path); existing == target {
142 return nil 177 return nil
143 } 178 }
144 if _, err := f.EnsureDirectory(filepath.Dir(path)); err != nil { 179 if _, err := f.EnsureDirectory(filepath.Dir(path)); err != nil {
145 return err 180 return err
146 } 181 }
147 182
148 // Create a new symlink file, can't modify existing one in place. 183 // Create a new symlink file, can't modify existing one in place.
149 temp := fmt.Sprintf("%s_%s", path, pseudoRand()) 184 temp := fmt.Sprintf("%s_%s", path, pseudoRand())
150 if err := os.Symlink(target, temp); err != nil { 185 if err := os.Symlink(target, temp); err != nil {
151 return err 186 return err
152 } 187 }
153 188
154 » // Atomically replace the current symlink with a new one. 189 » // Replace the current symlink with a new one. Use nuclear version (f.Re place)
155 » if err := os.Rename(temp, path); err != nil { 190 » // instead of simple atomicReplace to handle various edge cases handled by
156 » » err2 := os.Remove(temp) 191 » // the nuclear version (e.g replacing a non-empty directory).
Vadim Sh. 2015/07/28 01:20:18 it's a prep work for "replace locked files". The c
157 » » if err2 != nil { 192 » if err := f.Replace(temp, path); err != nil {
193 » » if err2 := os.Remove(temp); err2 != nil && !os.IsNotExist(err2) {
158 f.logger.Warningf("fs: failed to remove %s - %s", temp, err2) 194 f.logger.Warningf("fs: failed to remove %s - %s", temp, err2)
159 } 195 }
160 return err 196 return err
161 } 197 }
162 198
163 return nil 199 return nil
164 } 200 }
165 201
166 func (f *fsImpl) EnsureFileGone(path string) error { 202 func (f *fsImpl) EnsureFileGone(path string) error {
167 path, err := f.CwdRelToAbs(path) 203 path, err := f.CwdRelToAbs(path)
168 if err != nil { 204 if err != nil {
169 return err 205 return err
170 } 206 }
171 » err = os.Remove(path) 207 » if err = os.Remove(path); err != nil && !os.IsNotExist(err) {
172 » if err != nil && !os.IsNotExist(err) {
173 f.logger.Warningf("fs: failed to remove %s - %s", path, err) 208 f.logger.Warningf("fs: failed to remove %s - %s", path, err)
174 return err 209 return err
175 } 210 }
176 return nil 211 return nil
177 } 212 }
178 213
179 func (f *fsImpl) EnsureDirectoryGone(path string) error { 214 func (f *fsImpl) EnsureDirectoryGone(path string) error {
180 path, err := f.CwdRelToAbs(path) 215 path, err := f.CwdRelToAbs(path)
181 if err != nil { 216 if err != nil {
182 return err 217 return err
183 } 218 }
184 // Make directory "disappear" instantly by renaming it first. 219 // Make directory "disappear" instantly by renaming it first.
185 temp := fmt.Sprintf("%s_%v", path, pseudoRand()) 220 temp := fmt.Sprintf("%s_%v", path, pseudoRand())
186 » if err = os.Rename(path, temp); err != nil { 221 » if err = atomicRename(path, temp); err != nil {
187 if os.IsNotExist(err) { 222 if os.IsNotExist(err) {
188 return nil 223 return nil
189 } 224 }
190 f.logger.Warningf("fs: failed to rename directory %s - %s", path , err) 225 f.logger.Warningf("fs: failed to rename directory %s - %s", path , err)
191 return err 226 return err
192 } 227 }
193 if err = os.RemoveAll(temp); err != nil { 228 if err = os.RemoveAll(temp); err != nil {
194 f.logger.Warningf("fs: failed to remove directory %s - %s", temp , err) 229 f.logger.Warningf("fs: failed to remove directory %s - %s", temp , err)
195 return err 230 return err
196 } 231 }
(...skipping 17 matching lines...) Expand all
214 if _, err = os.Lstat(oldpath); err != nil { 249 if _, err = os.Lstat(oldpath); err != nil {
215 return err 250 return err
216 } 251 }
217 252
218 // Make parent directory of newpath. 253 // Make parent directory of newpath.
219 if _, err = f.EnsureDirectory(filepath.Dir(newpath)); err != nil { 254 if _, err = f.EnsureDirectory(filepath.Dir(newpath)); err != nil {
220 return err 255 return err
221 } 256 }
222 257
223 // Try a regular move first. Replaces files and empty directories. 258 // Try a regular move first. Replaces files and empty directories.
224 » if err = os.Rename(oldpath, newpath); err == nil { 259 » if err = atomicRename(oldpath, newpath); err == nil {
225 return nil 260 return nil
226 } 261 }
227 262
228 // Move existing path away, if it is there. 263 // Move existing path away, if it is there.
229 temp := fmt.Sprintf("%s_%s", newpath, pseudoRand()) 264 temp := fmt.Sprintf("%s_%s", newpath, pseudoRand())
230 » if err = os.Rename(newpath, temp); err != nil { 265 » if err = atomicRename(newpath, temp); err != nil {
231 if !os.IsNotExist(err) { 266 if !os.IsNotExist(err) {
232 f.logger.Warningf("fs: failed to rename(%v, %v) - %s", n ewpath, temp, err) 267 f.logger.Warningf("fs: failed to rename(%v, %v) - %s", n ewpath, temp, err)
233 return err 268 return err
234 } 269 }
235 temp = "" 270 temp = ""
236 } 271 }
237 272
238 // 'newpath' now should be available. 273 // 'newpath' now should be available.
239 » if err := os.Rename(oldpath, newpath); err != nil { 274 » if err := atomicRename(oldpath, newpath); err != nil {
240 f.logger.Warningf("fs: failed to rename(%v, %v) - %s", oldpath, newpath, err) 275 f.logger.Warningf("fs: failed to rename(%v, %v) - %s", oldpath, newpath, err)
241 // Try to return the path back... May be too late already. 276 // Try to return the path back... May be too late already.
242 if temp != "" { 277 if temp != "" {
243 » » » if err := os.Rename(temp, newpath); err != nil { 278 » » » if err := atomicRename(temp, newpath); err != nil {
244 f.logger.Errorf("fs: failed to rename(%v, %v) af ter unsuccessful move - %s", temp, newpath, err) 279 f.logger.Errorf("fs: failed to rename(%v, %v) af ter unsuccessful move - %s", temp, newpath, err)
245 } 280 }
246 } 281 }
247 return err 282 return err
248 } 283 }
249 284
250 // Cleanup the garbage left. Not a error if fails. 285 // Cleanup the garbage left. Not a error if fails.
251 if temp != "" { 286 if temp != "" {
252 if err := f.EnsureDirectoryGone(temp); err != nil { 287 if err := f.EnsureDirectoryGone(temp); err != nil {
253 f.logger.Warningf("fs: failed to cleanup garbage after f ile replace - %s", err) 288 f.logger.Warningf("fs: failed to cleanup garbage after f ile replace - %s", err)
(...skipping 14 matching lines...) Expand all
268 func pseudoRand() string { 303 func pseudoRand() string {
269 ts := time.Now().UnixNano() 304 ts := time.Now().UnixNano()
270 lastUsedTimeLock.Lock() 305 lastUsedTimeLock.Lock()
271 if ts <= lastUsedTime { 306 if ts <= lastUsedTime {
272 ts = lastUsedTime + 1 307 ts = lastUsedTime + 1
273 } 308 }
274 lastUsedTime = ts 309 lastUsedTime = ts
275 lastUsedTimeLock.Unlock() 310 lastUsedTimeLock.Unlock()
276 return fmt.Sprintf("%v_%v", os.Getpid(), ts) 311 return fmt.Sprintf("%v_%v", os.Getpid(), ts)
277 } 312 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698