forked from keybase/client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
path.go
206 lines (176 loc) · 5.98 KB
/
path.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
package libkbfs
import (
"fmt"
"strings"
"github.com/keybase/client/go/kbfs/tlf"
)
// PathType describes the types for different paths
type PathType string
const (
// KeybasePathType is the keybase root (like /keybase)
KeybasePathType PathType = "keybase"
// PublicPathType is the keybase public folder list (like /keybase/public)
PublicPathType PathType = "public"
// PrivatePathType is the keybase private folder list (like
// /keybase/private)
PrivatePathType PathType = "private"
// SingleTeamPathType is the keybase team folder list (like /keybase/teams)
SingleTeamPathType PathType = "team"
)
// BuildCanonicalPath returns a canonical path for a path components.
// This a canonical path and may need to be converted to a platform
// specific path, for example, on Windows, this might correspond to
// k:\private\username.
func BuildCanonicalPath(pathType PathType, paths ...string) string {
var prefix string
switch pathType {
case KeybasePathType:
prefix = "/" + string(KeybasePathType)
default:
prefix = "/" + string(KeybasePathType) + "/" + string(pathType)
}
pathElements := []string{prefix}
for _, p := range paths {
if p != "" {
pathElements = append(pathElements, p)
}
}
return strings.Join(pathElements, "/")
}
func buildCanonicalPathForTlfType(t tlf.Type, paths ...string) string {
var pathType PathType
switch t {
case tlf.Private:
pathType = PrivatePathType
case tlf.Public:
pathType = PublicPathType
case tlf.SingleTeam:
pathType = SingleTeamPathType
default:
panic(fmt.Sprintf("Unknown tlf path type: %d", t))
}
return BuildCanonicalPath(pathType, paths...)
}
// buildCanonicalPathForTlfName returns a canonical path for a tlf.
func buildCanonicalPathForTlfName(t tlf.Type, tlfName tlf.CanonicalName) string {
return buildCanonicalPathForTlfType(t, string(tlfName))
}
func buildCanonicalPathForTlf(tlf tlf.ID, paths ...string) string {
return buildCanonicalPathForTlfType(tlf.Type(), paths...)
}
// path represents the full KBFS path to a particular location, so
// that a flush can traverse backwards and fix up ids along the way.
type path struct {
FolderBranch
path []pathNode
}
// isValid() returns true if the path has at least one node (for the
// root).
func (p path) isValid() bool {
if len(p.path) < 1 {
return false
}
for _, n := range p.path {
if !n.isValid() {
return false
}
}
return true
}
// isValidForNotification() returns true if the path has at least one
// node (for the root), and the first element of the path is non-empty
// and does not start with "<", which indicates an unnotifiable path.
func (p path) isValidForNotification() bool {
if !p.isValid() {
return false
}
if p.Tlf == (tlf.NullID) {
return false
}
return len(p.path[0].Name) > 0 && !strings.HasPrefix(p.path[0].Name, "<")
}
// hasValidParent() returns true if this path is valid and
// parentPath() is a valid path.
func (p path) hasValidParent() bool {
return len(p.path) >= 2 && p.parentPath().isValid()
}
// tailName returns the name of the final node in the Path. Must be
// called with a valid path.
func (p path) tailName() string {
return p.path[len(p.path)-1].Name
}
// tailPointer returns the BlockPointer of the final node in the Path.
// Must be called with a valid path.
func (p path) tailPointer() BlockPointer {
return p.path[len(p.path)-1].BlockPointer
}
// tailRef returns the BlockRef of the final node in the Path. Must
// be called with a valid path.
func (p path) tailRef() BlockRef {
return p.path[len(p.path)-1].Ref()
}
// DebugString returns a string representation of the path with all
// branch and pointer information.
func (p path) DebugString() string {
debugNames := make([]string, 0, len(p.path))
for _, node := range p.path {
debugNames = append(debugNames, node.DebugString())
}
return fmt.Sprintf("%s:%s", p.FolderBranch, strings.Join(debugNames, "/"))
}
// String implements the fmt.Stringer interface for Path.
func (p path) String() string {
names := make([]string, 0, len(p.path))
for _, node := range p.path {
names = append(names, node.Name)
}
return strings.Join(names, "/")
}
// CanonicalPathString returns canonical representation of the full path,
// always prefaced by /keybase. This may require conversion to a platform
// specific path, for example, by replacing /keybase with the appropriate drive
// letter on Windows. It also, might need conversion if on a different run mode,
// for example, /keybase.staging on Unix type platforms.
func (p path) CanonicalPathString() string {
return buildCanonicalPathForTlf(p.Tlf, p.String())
}
// parentPath returns a new Path representing the parent subdirectory
// of this Path. Must be called with a valid path. Should not be
// called with a path of only a single node, as that would produce an
// invalid path.
func (p path) parentPath() *path {
return &path{p.FolderBranch, p.path[:len(p.path)-1]}
}
// ChildPath returns a new Path with the addition of a new entry
// with the given name and BlockPointer.
func (p path) ChildPath(name string, ptr BlockPointer) path {
child := path{
FolderBranch: p.FolderBranch,
path: make([]pathNode, len(p.path), len(p.path)+1),
}
copy(child.path, p.path)
child.path = append(child.path, pathNode{Name: name, BlockPointer: ptr})
return child
}
// ChildPathNoPtr returns a new Path with the addition of a new entry
// with the given name. That final PathNode will have no BlockPointer.
func (p path) ChildPathNoPtr(name string) path {
return p.ChildPath(name, BlockPointer{})
}
// PathNode is a single node along an KBFS path, pointing to the top
// block for that node of the path.
type pathNode struct {
BlockPointer
Name string
}
func (n pathNode) isValid() bool {
return n.BlockPointer.IsValid()
}
// DebugString returns a string representation of the node with all
// pointer information.
func (n pathNode) DebugString() string {
return fmt.Sprintf("%s(ptr=%s)", n.Name, n.BlockPointer)
}