Avoid filepath.Abs
filepath.Abs is surprisingly expensive, it calls os.Getwd every
time, which involves multiple syscalls, a lock, and and allocations.
Use IsAbs and prefix matching instead.
Test: paths_test.go
Change-Id: Ia6cf34d6bef24c694702af1e7a6ff08ffd2d822b
diff --git a/android/paths.go b/android/paths.go
index 13b31c7..4b84c97 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -503,16 +503,9 @@
return ret, err
}
- abs, err := filepath.Abs(ret.String())
- if err != nil {
- return ret, err
- }
- buildroot, err := filepath.Abs(ctx.Config().buildDir)
- if err != nil {
- return ret, err
- }
- if strings.HasPrefix(abs, buildroot) {
- return ret, fmt.Errorf("source path %s is in output", abs)
+ // absolute path already checked by validateSafePath
+ if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
+ return ret, fmt.Errorf("source path %s is in output", ret.String())
}
return ret, err
@@ -526,16 +519,9 @@
return ret, err
}
- abs, err := filepath.Abs(ret.String())
- if err != nil {
- return ret, err
- }
- buildroot, err := filepath.Abs(ctx.Config().buildDir)
- if err != nil {
- return ret, err
- }
- if strings.HasPrefix(abs, buildroot) {
- return ret, fmt.Errorf("source path %s is in output", abs)
+ // absolute path already checked by validatePath
+ if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
+ return ret, fmt.Errorf("source path %s is in output", ret.String())
}
return ret, nil
diff --git a/android/paths_test.go b/android/paths_test.go
index c4332d2..1ed0734 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -630,3 +630,64 @@
})
}
}
+
+func TestPathForSource(t *testing.T) {
+ testCases := []struct {
+ name string
+ buildDir string
+ src string
+ err string
+ }{
+ {
+ name: "normal",
+ buildDir: "out",
+ src: "a/b/c",
+ },
+ {
+ name: "abs",
+ buildDir: "out",
+ src: "/a/b/c",
+ err: "is outside directory",
+ },
+ {
+ name: "in out dir",
+ buildDir: "out",
+ src: "out/a/b/c",
+ err: "is in output",
+ },
+ }
+
+ funcs := []struct {
+ name string
+ f func(ctx PathContext, pathComponents ...string) (SourcePath, error)
+ }{
+ {"pathForSource", pathForSource},
+ {"safePathForSource", safePathForSource},
+ }
+
+ for _, f := range funcs {
+ t.Run(f.name, func(t *testing.T) {
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ testConfig := TestConfig(test.buildDir, nil)
+ ctx := &configErrorWrapper{config: testConfig}
+ _, err := f.f(ctx, test.src)
+ if len(ctx.errors) > 0 {
+ t.Fatalf("unexpected errors %v", ctx.errors)
+ }
+ if err != nil {
+ if test.err == "" {
+ t.Fatalf("unexpected error %q", err.Error())
+ } else if !strings.Contains(err.Error(), test.err) {
+ t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
+ }
+ } else {
+ if test.err != "" {
+ t.Fatalf("missing error %q", test.err)
+ }
+ }
+ })
+ }
+ })
+ }
+}