diff --git a/pkg/util/path.go b/pkg/util/path.go index 61d668d70c..73b81a9c28 100644 --- a/pkg/util/path.go +++ b/pkg/util/path.go @@ -5,6 +5,7 @@ import ( "os" "os/user" "path/filepath" + "runtime" "strings" "unicode/utf8" ) @@ -37,20 +38,27 @@ func ExpandPath(path string) string { } func SplitFilepath(path string) (result []string) { + separator := os.PathSeparator + path = filepath.FromSlash(path) path = filepath.Clean(path) - if filepath.IsAbs(path) { - p, err := filepath.Rel(string(os.PathSeparator), path) + if runtime.GOOS == "windows" { + sepStr := string(separator) + uncRootPath := fmt.Sprintf("%s%s", sepStr, sepStr) + + path = strings.TrimPrefix(path, uncRootPath) + path = strings.TrimPrefix(path, sepStr) + path = strings.TrimSuffix(path, sepStr) + } else if filepath.IsAbs(path) { + p, err := filepath.Rel(string(separator), path) if err != nil { panic(fmt.Sprintf("unable to get relative path for %q", path)) } path = p } - separator := os.PathSeparator - - if path == "." || path == string(separator) { + if path == "" || path == "." || path == string(separator) { return nil } diff --git a/pkg/util/path_test.go b/pkg/util/path_unix_test.go similarity index 91% rename from pkg/util/path_test.go rename to pkg/util/path_unix_test.go index ca7088d583..6b234221dd 100644 --- a/pkg/util/path_test.go +++ b/pkg/util/path_unix_test.go @@ -1,3 +1,5 @@ +//go:build !windows + package util_test import ( @@ -55,7 +57,7 @@ type splitPathTest struct { expectedPathParts []string } -var _ = DescribeTable("split path", +var _ = DescribeTable("split unix path", func(t splitPathTest) { parts := util.SplitFilepath(t.path) Expect(parts).To(Equal(t.expectedPathParts)) @@ -64,6 +66,10 @@ var _ = DescribeTable("split path", path: "/", expectedPathParts: nil, }), + Entry("root dir", splitPathTest{ + path: "/mydir/", + expectedPathParts: []string{"mydir"}, + }), Entry("unnormalized root path", splitPathTest{ path: "////", expectedPathParts: nil, diff --git a/pkg/util/path_windows_test.go b/pkg/util/path_windows_test.go new file mode 100644 index 0000000000..f5e5edcd20 --- /dev/null +++ b/pkg/util/path_windows_test.go @@ -0,0 +1,58 @@ +//go:build windows + +package util_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/werf/werf/pkg/util" +) + +type splitPathTest struct { + path string + expectedPathParts []string +} + +var _ = DescribeTable("split windows path", + func(t splitPathTest) { + parts := util.SplitFilepath(t.path) + Expect(parts).To(Equal(t.expectedPathParts)) + }, + Entry("UNC absolute path", splitPathTest{ + path: `\\Server2\Share\Test\Foo.txt`, + expectedPathParts: []string{"Server2", "Share", "Test", "Foo.txt"}, + }), + Entry("UNC absolute non-normalized path", splitPathTest{ + path: `\\\\\\Server2\\\Share\\\Test\Foo.txt`, + expectedPathParts: []string{"Server2", "Share", "Test", "Foo.txt"}, + }), + Entry("UNC root path", splitPathTest{ + path: `\\`, + expectedPathParts: nil, + }), + Entry("root disk path", splitPathTest{ + path: `D:\`, + expectedPathParts: []string{`D:`}, + }), + Entry("unnormalized root disk path", splitPathTest{ + path: `D:\\\\\\`, + expectedPathParts: []string{`D:`}, + }), + Entry("empty path", splitPathTest{ + path: "", + expectedPathParts: nil, + }), + Entry("absolute path to file", splitPathTest{ + path: `D:\path\to\file`, + expectedPathParts: []string{`D:`, "path", "to", "file"}, + }), + Entry("absolute path to dir", splitPathTest{ + path: `D:\path\to\dir\`, + expectedPathParts: []string{`D:`, "path", "to", "dir"}, + }), + Entry("relative path", splitPathTest{ + path: `path\to\dir\or\file`, + expectedPathParts: []string{"path", "to", "dir", "or", "file"}, + }), +)