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

Unified Diff: vpython/filesystem/filesystem.go

Issue 2703793003: vpython: Add filesystem operation / test packages. (Closed)
Patch Set: test now path Created 3 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | vpython/filesystem/filesystem_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: vpython/filesystem/filesystem.go
diff --git a/vpython/filesystem/filesystem.go b/vpython/filesystem/filesystem.go
new file mode 100644
index 0000000000000000000000000000000000000000..06128ac792b6c92c7f85bbf3cf5ad1e44f15b6bc
--- /dev/null
+++ b/vpython/filesystem/filesystem.go
@@ -0,0 +1,147 @@
+// Copyright 2017 The LUCI Authors. All rights reserved.
+// Use of this source code is governed under the Apache License, Version 2.0
+// that can be found in the LICENSE file.
+
+package filesystem
+
+import (
+ "os"
+ "path/filepath"
+ "time"
+
+ "github.com/luci/luci-go/common/errors"
+)
+
+// IsNotExist calls os.IsNotExist on the unwrapped err.
+func IsNotExist(err error) bool { return os.IsNotExist(errors.Unwrap(err)) }
+
+// MakeDirs is a convenience wrapper around os.MkdirAll that applies a 0755
+// mask to all created directories.
+func MakeDirs(path string) error {
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return errors.Annotate(err).Err()
+ }
+ return nil
+}
+
+// AbsPath is a convenience wrapper around filepath.Abs that accepts a string
+// pointer, base, and updates it on successful resolution.
+func AbsPath(base *string) error {
+ v, err := filepath.Abs(*base)
+ if err != nil {
+ return errors.Annotate(err).Reason("unable to resolve absolute path").
+ D("base", *base).
+ Err()
+ }
+ *base = v
+ return nil
+}
+
+// Touch creates a new, empty file at the specified path.
+//
+// If when is zero-value, time.Now will be used.
+func Touch(path string, when time.Time, mode os.FileMode) error {
+ // Try and create a file at the target path.
+ fd, err := os.OpenFile(path, (os.O_CREATE | os.O_RDWR | os.O_TRUNC), mode)
+ if err == nil {
+ if err := fd.Close(); err != nil {
+ return errors.Annotate(err).Reason("failed to close new file").Err()
+ }
+ if when.IsZero() {
+ // If "now" was specified, and we created a new file, then its times will
+ // be now by default.
+ return nil
+ }
+ }
+
+ // Couldn't create a new file. Either it exists already, it is a directory,
+ // or there was an OS-level failure. Since we can't really distinguish
+ // between these cases, try opening for write (update timestamp) and error
+ // if this fails.
+ if when.IsZero() {
+ when = time.Now()
+ }
+ if err := os.Chtimes(path, when, when); err != nil {
+ return errors.Annotate(err).Reason("failed to Chtimes").
+ D("path", path).
+ Err()
+ }
+ return nil
+}
+
+// RemoveAll is a wrapper around os.RemoveAll which makes sure all files are
+// writeable (recursively) prior to removing them.
+func RemoveAll(path string) error {
+ err := removeAllImpl(path, func(path string, fi os.FileInfo) error {
+ // If we aren't handed a FileInfo, use Lstat to get one.
+ if fi == nil {
+ var err error
+ if fi, err = os.Lstat(path); err != nil {
+ return errors.Annotate(err).Reason("could not Lstat path").
+ D("path", path).
+ Err()
+ }
+ }
+
+ // Make user-writable, if it's not already.
+ mode := fi.Mode()
+ if (mode & 0200) == 0 {
+ mode |= 0200
+ if err := os.Chmod(path, mode); err != nil {
+ return errors.Annotate(err).Reason("could not Chmod path").
+ D("mode", mode).
+ D("path", path).
+ Err()
+ }
+ }
+
+ if err := os.Remove(path); err != nil {
+ return errors.Annotate(err).Reason("failed to remove path").
+ D("path", path).
+ Err()
+ }
+ return nil
+ })
+ if err != nil {
+ return errors.Annotate(err).Reason("failed to recurisvely remove path").
+ D("path", path).
+ Err()
+ }
+ return nil
+}
+
+// MakeReadOnly recursively iterates through all of the files and directories
+// starting at path and marks them read-only.
+func MakeReadOnly(path string, filter func(string) bool) error {
+ return recursiveChmod(path, filter, func(mode os.FileMode) os.FileMode {
+ return mode & (^os.FileMode(0222))
+ })
+}
+
+func recursiveChmod(path string, filter func(string) bool, chmod func(mode os.FileMode) os.FileMode) error {
+ if filter == nil {
+ filter = func(string) bool { return true }
+ }
+
+ err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return errors.Annotate(err).Err()
+ }
+
+ mode := info.Mode()
+ if (mode.IsRegular() || mode.IsDir()) && filter(path) {
+ if newMode := chmod(mode); newMode != mode {
+ if err := os.Chmod(path, newMode); err != nil {
+ return errors.Annotate(err).Reason("failed to Chmod").
+ D("path", path).
+ Err()
+ }
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ return errors.Annotate(err).Err()
+ }
+ return nil
+}
« no previous file with comments | « no previous file | vpython/filesystem/filesystem_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698