Allow primary builder to change working directory
Bug: 146437378
Test: pathtools/fs_test.go
Change-Id: I513ceb9b8b0b4f18223bc34ecad9846fe220709b
diff --git a/pathtools/fs.go b/pathtools/fs.go
index 8329392..b45c4a5 100644
--- a/pathtools/fs.go
+++ b/pathtools/fs.go
@@ -36,7 +36,7 @@
DontFollowSymlinks = ShouldFollowSymlinks(false)
)
-var OsFs FileSystem = osFs{}
+var OsFs FileSystem = &osFs{}
func MockFs(files map[string][]byte) FileSystem {
fs := &mockFs{
@@ -123,11 +123,45 @@
}
// osFs implements FileSystem using the local disk.
-type osFs struct{}
+type osFs struct {
+ srcDir string
+}
-func (osFs) Open(name string) (ReaderAtSeekerCloser, error) { return os.Open(name) }
-func (osFs) Exists(name string) (bool, bool, error) {
- stat, err := os.Stat(name)
+func NewOsFs(path string) FileSystem {
+ return &osFs{srcDir: path}
+}
+
+func (fs *osFs) removeSrcDirPrefix(path string) string {
+ if fs.srcDir == "" {
+ return path
+ }
+ rel, err := filepath.Rel(fs.srcDir, path)
+ if err != nil {
+ panic(fmt.Errorf("unexpected failure in removeSrcDirPrefix filepath.Rel(%s, %s): %s",
+ fs.srcDir, path, err))
+ }
+ if strings.HasPrefix(rel, "../") {
+ panic(fmt.Errorf("unexpected relative path outside directory in removeSrcDirPrefix filepath.Rel(%s, %s): %s",
+ fs.srcDir, path, rel))
+ }
+ return rel
+}
+
+func (fs *osFs) removeSrcDirPrefixes(paths []string) []string {
+ if fs.srcDir != "" {
+ for i, path := range paths {
+ paths[i] = fs.removeSrcDirPrefix(path)
+ }
+ }
+ return paths
+}
+
+func (fs *osFs) Open(name string) (ReaderAtSeekerCloser, error) {
+ return os.Open(filepath.Join(fs.srcDir, name))
+}
+
+func (fs *osFs) Exists(name string) (bool, bool, error) {
+ stat, err := os.Stat(filepath.Join(fs.srcDir, name))
if err == nil {
return true, stat.IsDir(), nil
} else if os.IsNotExist(err) {
@@ -137,45 +171,47 @@
}
}
-func (osFs) IsDir(name string) (bool, error) {
- info, err := os.Stat(name)
+func (fs *osFs) IsDir(name string) (bool, error) {
+ info, err := os.Stat(filepath.Join(fs.srcDir, name))
if err != nil {
return false, err
}
return info.IsDir(), nil
}
-func (osFs) IsSymlink(name string) (bool, error) {
- if info, err := os.Lstat(name); err != nil {
+func (fs *osFs) IsSymlink(name string) (bool, error) {
+ if info, err := os.Lstat(filepath.Join(fs.srcDir, name)); err != nil {
return false, err
} else {
return info.Mode()&os.ModeSymlink != 0, nil
}
}
-func (fs osFs) Glob(pattern string, excludes []string, follow ShouldFollowSymlinks) (matches, dirs []string, err error) {
+func (fs *osFs) Glob(pattern string, excludes []string, follow ShouldFollowSymlinks) (matches, dirs []string, err error) {
return startGlob(fs, pattern, excludes, follow)
}
-func (osFs) glob(pattern string) ([]string, error) {
- return filepath.Glob(pattern)
+func (fs *osFs) glob(pattern string) ([]string, error) {
+ paths, err := filepath.Glob(filepath.Join(fs.srcDir, pattern))
+ fs.removeSrcDirPrefixes(paths)
+ return paths, err
}
-func (osFs) Lstat(path string) (stats os.FileInfo, err error) {
- return os.Lstat(path)
+func (fs *osFs) Lstat(path string) (stats os.FileInfo, err error) {
+ return os.Lstat(filepath.Join(fs.srcDir, path))
}
-func (osFs) Stat(path string) (stats os.FileInfo, err error) {
- return os.Stat(path)
+func (fs *osFs) Stat(path string) (stats os.FileInfo, err error) {
+ return os.Stat(filepath.Join(fs.srcDir, path))
}
// Returns a list of all directories under dir
-func (osFs) ListDirsRecursive(name string, follow ShouldFollowSymlinks) (dirs []string, err error) {
- return listDirsRecursive(OsFs, name, follow)
+func (fs *osFs) ListDirsRecursive(name string, follow ShouldFollowSymlinks) (dirs []string, err error) {
+ return listDirsRecursive(fs, name, follow)
}
-func (osFs) ReadDirNames(name string) ([]string, error) {
- dir, err := os.Open(name)
+func (fs *osFs) ReadDirNames(name string) ([]string, error) {
+ dir, err := os.Open(filepath.Join(fs.srcDir, name))
if err != nil {
return nil, err
}
@@ -190,8 +226,8 @@
return contents, nil
}
-func (osFs) Readlink(name string) (string, error) {
- return os.Readlink(name)
+func (fs *osFs) Readlink(name string) (string, error) {
+ return os.Readlink(filepath.Join(fs.srcDir, name))
}
type mockFs struct {
diff --git a/pathtools/fs_test.go b/pathtools/fs_test.go
index 1b5c458..a9a7060 100644
--- a/pathtools/fs_test.go
+++ b/pathtools/fs_test.go
@@ -22,6 +22,8 @@
"testing"
)
+const testdataDir = "testdata/dangling"
+
func symlinkMockFs() *mockFs {
files := []string{
"a/a/a",
@@ -149,25 +151,37 @@
}
mock := symlinkMockFs()
- fsList := []FileSystem{mock, OsFs}
- names := []string{"mock", "os"}
- os.Chdir("testdata/dangling")
- defer os.Chdir("../..")
-
- for i, fs := range fsList {
- t.Run(names[i], func(t *testing.T) {
- for _, test := range testCases {
- t.Run(test.name, func(t *testing.T) {
- got, err := fs.IsDir(test.name)
- checkErr(t, test.err, err)
- if got != test.isDir {
- t.Errorf("want: %v, got %v", test.isDir, got)
- }
- })
- }
- })
+ run := func(t *testing.T, fs FileSystem) {
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ got, err := fs.IsDir(test.name)
+ checkErr(t, test.err, err)
+ if got != test.isDir {
+ t.Errorf("want: %v, got %v", test.isDir, got)
+ }
+ })
+ }
}
+
+ t.Run("mock", func(t *testing.T) {
+ run(t, mock)
+ })
+
+ t.Run("os", func(t *testing.T) {
+ os.Chdir("testdata/dangling")
+ defer os.Chdir("../..")
+ run(t, OsFs)
+ })
+
+ t.Run("os relative srcDir", func(t *testing.T) {
+ run(t, NewOsFs(testdataDir))
+ })
+
+ t.Run("os absolute srcDir", func(t *testing.T) {
+ wd, _ := os.Getwd()
+ run(t, NewOsFs(filepath.Join(wd, testdataDir)))
+ })
}
func TestFs_ListDirsRecursiveFollowSymlinks(t *testing.T) {
@@ -200,26 +214,37 @@
}
mock := symlinkMockFs()
- fsList := []FileSystem{mock, OsFs}
- names := []string{"mock", "os"}
- os.Chdir("testdata/dangling")
- defer os.Chdir("../..")
-
- for i, fs := range fsList {
- t.Run(names[i], func(t *testing.T) {
-
- for _, test := range testCases {
- t.Run(test.name, func(t *testing.T) {
- got, err := fs.ListDirsRecursive(test.name, FollowSymlinks)
- checkErr(t, test.err, err)
- if !reflect.DeepEqual(got, test.dirs) {
- t.Errorf("want: %v, got %v", test.dirs, got)
- }
- })
- }
- })
+ run := func(t *testing.T, fs FileSystem) {
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ got, err := fs.ListDirsRecursive(test.name, FollowSymlinks)
+ checkErr(t, test.err, err)
+ if !reflect.DeepEqual(got, test.dirs) {
+ t.Errorf("want: %v, got %v", test.dirs, got)
+ }
+ })
+ }
}
+
+ t.Run("mock", func(t *testing.T) {
+ run(t, mock)
+ })
+
+ t.Run("os", func(t *testing.T) {
+ os.Chdir("testdata/dangling")
+ defer os.Chdir("../..")
+ run(t, OsFs)
+ })
+
+ t.Run("os relative srcDir", func(t *testing.T) {
+ run(t, NewOsFs(testdataDir))
+ })
+
+ t.Run("os absolute srcDir", func(t *testing.T) {
+ wd, _ := os.Getwd()
+ run(t, NewOsFs(filepath.Join(wd, testdataDir)))
+ })
}
func TestFs_ListDirsRecursiveDontFollowSymlinks(t *testing.T) {
@@ -252,26 +277,37 @@
}
mock := symlinkMockFs()
- fsList := []FileSystem{mock, OsFs}
- names := []string{"mock", "os"}
- os.Chdir("testdata/dangling")
- defer os.Chdir("../..")
-
- for i, fs := range fsList {
- t.Run(names[i], func(t *testing.T) {
-
- for _, test := range testCases {
- t.Run(test.name, func(t *testing.T) {
- got, err := fs.ListDirsRecursive(test.name, DontFollowSymlinks)
- checkErr(t, test.err, err)
- if !reflect.DeepEqual(got, test.dirs) {
- t.Errorf("want: %v, got %v", test.dirs, got)
- }
- })
- }
- })
+ run := func(t *testing.T, fs FileSystem) {
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ got, err := fs.ListDirsRecursive(test.name, DontFollowSymlinks)
+ checkErr(t, test.err, err)
+ if !reflect.DeepEqual(got, test.dirs) {
+ t.Errorf("want: %v, got %v", test.dirs, got)
+ }
+ })
+ }
}
+
+ t.Run("mock", func(t *testing.T) {
+ run(t, mock)
+ })
+
+ t.Run("os", func(t *testing.T) {
+ os.Chdir("testdata/dangling")
+ defer os.Chdir("../..")
+ run(t, OsFs)
+ })
+
+ t.Run("os relative srcDir", func(t *testing.T) {
+ run(t, NewOsFs(testdataDir))
+ })
+
+ t.Run("os absolute srcDir", func(t *testing.T) {
+ wd, _ := os.Getwd()
+ run(t, NewOsFs(filepath.Join(wd, testdataDir)))
+ })
}
func TestFs_Readlink(t *testing.T) {
@@ -321,26 +357,37 @@
}
mock := symlinkMockFs()
- fsList := []FileSystem{mock, OsFs}
- names := []string{"mock", "os"}
- os.Chdir("testdata/dangling")
- defer os.Chdir("../..")
-
- for i, fs := range fsList {
- t.Run(names[i], func(t *testing.T) {
-
- for _, test := range testCases {
- t.Run(test.from, func(t *testing.T) {
- got, err := fs.Readlink(test.from)
- checkErr(t, test.err, err)
- if got != test.to {
- t.Errorf("fs.Readlink(%q) want: %q, got %q", test.from, test.to, got)
- }
- })
- }
- })
+ run := func(t *testing.T, fs FileSystem) {
+ for _, test := range testCases {
+ t.Run(test.from, func(t *testing.T) {
+ got, err := fs.Readlink(test.from)
+ checkErr(t, test.err, err)
+ if got != test.to {
+ t.Errorf("fs.Readlink(%q) want: %q, got %q", test.from, test.to, got)
+ }
+ })
+ }
}
+
+ t.Run("mock", func(t *testing.T) {
+ run(t, mock)
+ })
+
+ t.Run("os", func(t *testing.T) {
+ os.Chdir("testdata/dangling")
+ defer os.Chdir("../..")
+ run(t, OsFs)
+ })
+
+ t.Run("os relative srcDir", func(t *testing.T) {
+ run(t, NewOsFs(testdataDir))
+ })
+
+ t.Run("os absolute srcDir", func(t *testing.T) {
+ wd, _ := os.Getwd()
+ run(t, NewOsFs(filepath.Join(wd, testdataDir)))
+ })
}
func TestFs_Lstat(t *testing.T) {
@@ -392,33 +439,44 @@
}
mock := symlinkMockFs()
- fsList := []FileSystem{mock, OsFs}
- names := []string{"mock", "os"}
- os.Chdir("testdata/dangling")
- defer os.Chdir("../..")
-
- for i, fs := range fsList {
- t.Run(names[i], func(t *testing.T) {
-
- for _, test := range testCases {
- t.Run(test.name, func(t *testing.T) {
- got, err := fs.Lstat(test.name)
- checkErr(t, test.err, err)
- if err != nil {
- return
- }
- if got.Mode()&os.ModeType != test.mode {
- t.Errorf("fs.Lstat(%q).Mode()&os.ModeType want: %x, got %x",
- test.name, test.mode, got.Mode()&os.ModeType)
- }
- if test.mode == 0 && got.Size() != test.size {
- t.Errorf("fs.Lstat(%q).Size() want: %d, got %d", test.name, test.size, got.Size())
- }
- })
- }
- })
+ run := func(t *testing.T, fs FileSystem) {
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ got, err := fs.Lstat(test.name)
+ checkErr(t, test.err, err)
+ if err != nil {
+ return
+ }
+ if got.Mode()&os.ModeType != test.mode {
+ t.Errorf("fs.Lstat(%q).Mode()&os.ModeType want: %x, got %x",
+ test.name, test.mode, got.Mode()&os.ModeType)
+ }
+ if test.mode == 0 && got.Size() != test.size {
+ t.Errorf("fs.Lstat(%q).Size() want: %d, got %d", test.name, test.size, got.Size())
+ }
+ })
+ }
}
+
+ t.Run("mock", func(t *testing.T) {
+ run(t, mock)
+ })
+
+ t.Run("os", func(t *testing.T) {
+ os.Chdir("testdata/dangling")
+ defer os.Chdir("../..")
+ run(t, OsFs)
+ })
+
+ t.Run("os relative srcDir", func(t *testing.T) {
+ run(t, NewOsFs(testdataDir))
+ })
+
+ t.Run("os absolute srcDir", func(t *testing.T) {
+ wd, _ := os.Getwd()
+ run(t, NewOsFs(filepath.Join(wd, testdataDir)))
+ })
}
func TestFs_Stat(t *testing.T) {
@@ -470,33 +528,44 @@
}
mock := symlinkMockFs()
- fsList := []FileSystem{mock, OsFs}
- names := []string{"mock", "os"}
- os.Chdir("testdata/dangling")
- defer os.Chdir("../..")
-
- for i, fs := range fsList {
- t.Run(names[i], func(t *testing.T) {
-
- for _, test := range testCases {
- t.Run(test.name, func(t *testing.T) {
- got, err := fs.Stat(test.name)
- checkErr(t, test.err, err)
- if err != nil {
- return
- }
- if got.Mode()&os.ModeType != test.mode {
- t.Errorf("fs.Stat(%q).Mode()&os.ModeType want: %x, got %x",
- test.name, test.mode, got.Mode()&os.ModeType)
- }
- if test.mode == 0 && got.Size() != test.size {
- t.Errorf("fs.Stat(%q).Size() want: %d, got %d", test.name, test.size, got.Size())
- }
- })
- }
- })
+ run := func(t *testing.T, fs FileSystem) {
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ got, err := fs.Stat(test.name)
+ checkErr(t, test.err, err)
+ if err != nil {
+ return
+ }
+ if got.Mode()&os.ModeType != test.mode {
+ t.Errorf("fs.Stat(%q).Mode()&os.ModeType want: %x, got %x",
+ test.name, test.mode, got.Mode()&os.ModeType)
+ }
+ if test.mode == 0 && got.Size() != test.size {
+ t.Errorf("fs.Stat(%q).Size() want: %d, got %d", test.name, test.size, got.Size())
+ }
+ })
+ }
}
+
+ t.Run("mock", func(t *testing.T) {
+ run(t, mock)
+ })
+
+ t.Run("os", func(t *testing.T) {
+ os.Chdir("testdata/dangling")
+ defer os.Chdir("../..")
+ run(t, OsFs)
+ })
+
+ t.Run("os relative srcDir", func(t *testing.T) {
+ run(t, NewOsFs(testdataDir))
+ })
+
+ t.Run("os absolute srcDir", func(t *testing.T) {
+ wd, _ := os.Getwd()
+ run(t, NewOsFs(filepath.Join(wd, testdataDir)))
+ })
}
func TestMockFs_glob(t *testing.T) {
@@ -538,27 +607,39 @@
}
mock := symlinkMockFs()
- fsList := []FileSystem{mock, OsFs}
- names := []string{"mock", "os"}
- os.Chdir("testdata/dangling")
- defer os.Chdir("../..")
-
- for i, fs := range fsList {
- t.Run(names[i], func(t *testing.T) {
- for _, test := range testCases {
- t.Run(test.pattern, func(t *testing.T) {
- got, err := fs.glob(test.pattern)
- if err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(got, test.files) {
- t.Errorf("want: %v, got %v", test.files, got)
- }
- })
- }
- })
+ run := func(t *testing.T, fs FileSystem) {
+ for _, test := range testCases {
+ t.Run(test.pattern, func(t *testing.T) {
+ got, err := fs.glob(test.pattern)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(got, test.files) {
+ t.Errorf("want: %v, got %v", test.files, got)
+ }
+ })
+ }
}
+
+ t.Run("mock", func(t *testing.T) {
+ run(t, mock)
+ })
+
+ t.Run("os", func(t *testing.T) {
+ os.Chdir("testdata/dangling")
+ defer os.Chdir("../..")
+ run(t, OsFs)
+ })
+
+ t.Run("os relative srcDir", func(t *testing.T) {
+ run(t, NewOsFs(testdataDir))
+ })
+
+ t.Run("os absolute srcDir", func(t *testing.T) {
+ wd, _ := os.Getwd()
+ run(t, NewOsFs(filepath.Join(wd, testdataDir)))
+ })
}
func syscallError(err error) error {