-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdir.go
196 lines (177 loc) · 4.88 KB
/
dir.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
package wpk
import (
"errors"
"io"
"io/fs"
"os"
"path"
"regexp"
"strings"
)
// MakeTagsPath receives file path and returns it with ".wpt" extension.
// It hepls to open splitted package.
func MakeTagsPath(fpath string) string {
var ext = path.Ext(fpath)
return fpath[:len(fpath)-len(ext)] + ".wpt"
}
// MakeDataPath receives file path and returns it with ".wpf" extension.
// It hepls to open splitted package.
func MakeDataPath(fpath string) string {
var ext = path.Ext(fpath)
return fpath[:len(fpath)-len(ext)] + ".wpf"
}
// PackDirFile is a directory file whose entries can be read with the ReadDir method.
// fs.ReadDirFile interface implementation.
type PackDirFile struct {
*TagsetRaw // has fs.FileInfo interface
ftt *FTT
}
// fs.ReadDirFile interface implementation.
func (f *PackDirFile) Stat() (fs.FileInfo, error) {
return f, nil
}
// fs.ReadDirFile interface implementation.
func (f *PackDirFile) Read(b []byte) (n int, err error) {
return 0, io.EOF
}
// fs.ReadDirFile interface implementation.
func (f *PackDirFile) Close() error {
return nil
}
// fs.ReadDirFile interface implementation.
func (f *PackDirFile) ReadDir(n int) (matches []fs.DirEntry, err error) {
return f.ftt.ReadDirN(f.Path(), n)
}
var (
evlre = regexp.MustCompile(`\$\w+`) // env var with linux-like syntax
evure = regexp.MustCompile(`\$\{\w+\}`) // env var with unix-like syntax
evwre = regexp.MustCompile(`\%\w+\%`) // env var with windows-like syntax
)
// Envfmt replaces environment variables entries in file path to there values.
// Environment variables must be enclosed as ${...} in string.
func Envfmt(p string) string {
return evwre.ReplaceAllStringFunc(evure.ReplaceAllStringFunc(evlre.ReplaceAllStringFunc(p, func(name string) string {
// strip $VAR and replace by environment value
if val, ok := os.LookupEnv(name[1:]); ok {
return val
} else {
return name
}
}), func(name string) string {
// strip ${VAR} and replace by environment value
if val, ok := os.LookupEnv(name[2 : len(name)-1]); ok {
return val
} else {
return name
}
}), func(name string) string {
// strip %VAR% and replace by environment value
if val, ok := os.LookupEnv(name[1 : len(name)-1]); ok {
return val
} else {
return name
}
})
}
// PathExists check up file or directory existence.
func PathExists(path string) (bool, error) {
var err error
if _, err = os.Stat(path); err == nil {
return true, nil
}
if errors.Is(err, fs.ErrNotExist) {
return false, nil
}
return true, err
}
// TempPath returns filename located at temporary directory.
func TempPath(fname string) string {
return path.Join(ToSlash(os.TempDir()), fname)
}
// ToSlash brings filenames to true slashes
// without superfluous allocations if it possible.
func ToSlash(s string) string {
var b = S2B(s)
var bc = b
var c bool
for i, v := range b {
if v == '\\' {
if !c {
bc, c = []byte(s), true
}
bc[i] = '/'
}
}
return B2S(bc)
}
// Normalize brings file path to normalized form. Normalized path is the key to FTT map.
var Normalize = ToSlash
// ReadDirN returns fs.DirEntry array with nested into given package directory presentation.
// It's core function for ReadDirFile and ReadDirFS structures.
func (ftt *FTT) ReadDirN(fulldir string, n int) (list []fs.DirEntry, err error) {
var found = map[string]fs.DirEntry{}
var prefix string
if fulldir != "." && fulldir != "" {
prefix = Normalize(fulldir) + "/" // set terminated slash
}
ftt.rwm.Range(func(fkey string, ts *TagsetRaw) bool {
if strings.HasPrefix(fkey, prefix) {
var suffix = fkey[len(prefix):]
var sp = strings.IndexByte(suffix, '/')
if sp < 0 { // file detected
found[suffix] = ts
n--
} else { // dir detected
var subdir = path.Join(prefix, suffix[:sp])
if _, ok := found[subdir]; !ok {
var dts = MakeTagset(nil, 2, 2).
Put(TIDpath, StrTag(subdir))
var f = &PackDirFile{
TagsetRaw: dts,
ftt: ftt,
}
found[subdir] = f
n--
}
}
}
return n != 0
})
list = make([]fs.DirEntry, len(found))
var i int
for _, de := range found {
list[i] = de
i++
}
if n > 0 {
err = io.EOF
}
return
}
// OpenDir returns PackDirFile structure associated with group of files in package
// pooled with common directory prefix. Usable to implement fs.FileSystem interface.
func (ftt *FTT) OpenDir(fulldir string) (fs.ReadDirFile, error) {
var prefix string
if fulldir != "." && fulldir != "" {
prefix = Normalize(fulldir) + "/" // set terminated slash
}
var f *PackDirFile
ftt.rwm.Range(func(fkey string, ts *TagsetRaw) bool {
if strings.HasPrefix(fkey, prefix) {
var dts = MakeTagset(nil, 2, 2).
Put(TIDpath, StrTag(fulldir))
f = &PackDirFile{
TagsetRaw: dts,
ftt: ftt,
}
return false
}
return true
})
if f != nil {
return f, nil
}
// on case if not found
return nil, &fs.PathError{Op: "open", Path: fulldir, Err: fs.ErrNotExist}
}
// The End.