summaryrefslogtreecommitdiffhomepage
path: root/util/pathutil
diff options
context:
space:
mode:
authorPercy Wegmann <percy@tailscale.com>2023-12-21 15:57:01 -0600
committerPercy Wegmann <percy@tailscale.com>2024-02-02 12:33:48 -0600
commit857cef70c97fe019ea24f7b4f24252f4746ebcc3 (patch)
tree257a7ec87af6ad29c06cdfe0e8774259f5e83cc3 /util/pathutil
parent60657ac83f415555c19027b0b18c0fe2d15bf40a (diff)
downloadtailscale-flyingsquirrel_bak.tar.xz
tailscale-flyingsquirrel_bak.zip
tailfs: initial implementationflyingsquirrel_bak
Implemented WebDAV-based core of Tailfs Updates tailscale/corp#16827 Signed-off-by: Percy Wegmann <percy@tailscale.com>
Diffstat (limited to 'util/pathutil')
-rw-r--r--util/pathutil/pathutil.go28
-rw-r--r--util/pathutil/pathutil_test.go37
2 files changed, 65 insertions, 0 deletions
diff --git a/util/pathutil/pathutil.go b/util/pathutil/pathutil.go
new file mode 100644
index 000000000..6b3728d9f
--- /dev/null
+++ b/util/pathutil/pathutil.go
@@ -0,0 +1,28 @@
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+// package pathutil provides utility functions for working with URL paths.
+package pathutil
+
+import (
+ "path"
+ "strings"
+)
+
+const (
+ sepString = "/"
+ sepStringAndDot = "/."
+ sep = '/'
+)
+
+func Split(p string) []string {
+ return strings.Split(strings.Trim(path.Clean(p), sepStringAndDot), sepString)
+}
+
+func Join(parts ...string) string {
+ return sepString + strings.Join(parts, sepString)
+}
+
+func IsRoot(path string) bool {
+ return len(path) == 0 || len(path) == 1 && path[0] == sep
+}
diff --git a/util/pathutil/pathutil_test.go b/util/pathutil/pathutil_test.go
new file mode 100644
index 000000000..7ecc3787c
--- /dev/null
+++ b/util/pathutil/pathutil_test.go
@@ -0,0 +1,37 @@
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package pathutil
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestSplit(t *testing.T) {
+ tests := []struct {
+ path string
+ want []string
+ }{
+ {"", []string{""}},
+ {"/", []string{""}},
+ {"//", []string{""}},
+ {"a", []string{"a"}},
+ {"/a", []string{"a"}},
+ {"a/", []string{"a"}},
+ {"/a/", []string{"a"}},
+ {"a/b", []string{"a", "b"}},
+ {"/a/b", []string{"a", "b"}},
+ {"a/b/", []string{"a", "b"}},
+ {"/a/b/", []string{"a", "b"}},
+ {"/a/../b", []string{"b"}},
+ }
+ for _, tt := range tests {
+ t.Run(tt.path, func(t *testing.T) {
+ if got := Split(tt.path); !reflect.DeepEqual(tt.want, got) {
+ t.Errorf("Split(%q) = %v; want %v", tt.path, got, tt.want)
+ }
+ })
+ }
+
+}