-
Notifications
You must be signed in to change notification settings - Fork 288
/
ospath.go
158 lines (136 loc) · 3.32 KB
/
ospath.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
package ospath
import (
"os"
"path/filepath"
)
// Given absolute paths `dir` and `file`, returns
// the relative path of `file` relative to `dir`.
//
// Returns true if successful. If `file` is not under `dir`, returns false.
//
// TODO(nick): Should we have an assertion that dir and file are absolute? This is a common
// mistake when using this API. It won't work correctly with relative paths.
func Child(dir string, file string) (string, bool) {
if dir == "" {
return "", false
}
dir = filepath.Clean(dir)
current := filepath.Clean(file)
child := "."
for {
if dir == current {
return child, true
}
if len(current) <= len(dir) || current == "." {
return "", false
}
cDir := filepath.Dir(current)
cBase := filepath.Base(current)
child = filepath.Join(cBase, child)
current = cDir
}
}
// IsChildOfOne returns true if the given file is a child of the given directory
func IsChild(dir string, file string) bool {
_, ret := Child(dir, file)
return ret
}
// IsChildOfOne returns true if the given file is a child of (at least) one of
// the given directories.
func IsChildOfOne(dirs []string, file string) bool {
for _, dir := range dirs {
if IsChild(dir, file) {
return true
}
}
return false
}
func RealChild(dir string, file string) (string, bool, error) {
realDir, err := RealAbs(dir)
if err != nil {
return "", false, err
}
realFile, err := RealAbs(file)
if err != nil {
return "", false, err
}
rel, isChild := Child(realDir, realFile)
return rel, isChild, nil
}
// Returns the absolute version of this path, resolving all symlinks.
func RealAbs(path string) (string, error) {
// Make the path absolute first, so that we find any symlink parents.
absPath, err := filepath.Abs(path)
if err != nil {
return "", err
}
// Resolve the symlinks.
realPath, err := filepath.EvalSymlinks(absPath)
if err != nil {
return "", err
}
// Double-check we're still absolute.
return filepath.Abs(realPath)
}
// Like os.Getwd, but with all symlinks resolved.
func Realwd() (string, error) {
path, err := os.Getwd()
if err != nil {
return "", err
}
return RealAbs(path)
}
func IsRegularFile(path string) bool {
f, err := os.Stat(path)
if err != nil {
return false
}
return f.Mode().IsRegular()
}
func IsDir(path string) bool {
f, err := os.Stat(path)
if err != nil {
return false
}
return f.Mode().IsDir()
}
func IsBrokenSymlink(path string) (bool, error) {
// Stat resolves symlinks, lstat does not.
// So if Stat reports IsNotExist, but Lstat does not,
// then we have a broken symlink.
_, err := os.Stat(path)
if err == nil {
return false, nil
}
if !os.IsNotExist(err) {
return false, err
}
_, err = os.Lstat(path)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return true, nil
}
// TryAsCwdChildren converts the given absolute paths to children of the CWD,
// if possible (otherwise, leaves them as absolute paths).
func TryAsCwdChildren(absPaths []string) []string {
wd, err := os.Getwd()
if err != nil {
// This is just a util for printing right now, so don't actually throw an
// error, just return back all the absolute paths
return absPaths[:]
}
res := make([]string, len(absPaths))
for i, abs := range absPaths {
rel, isChild := Child(wd, abs)
if isChild {
res[i] = rel
} else {
res[i] = abs
}
}
return res
}