This repository has been archived by the owner on Aug 4, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
filemapfs.go
144 lines (129 loc) · 3.01 KB
/
filemapfs.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
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package mapfs file provides an implementation of the FileSystem
// interface based on the contents of a map[string]string.
package vfs // import "github.com/thomasf/vfs"
import (
"fmt"
"os"
pathpkg "path"
"sort"
"strings"
"github.com/pkg/errors"
)
// FileMap returns a new FileSystem from the provided Map. The Map value
// specifies the source location of a file. Map keys should be forward
// slash-separated pathnames and not contain a leading slash.
func FileMap(m map[string]string) FileSystem {
return filemapFS(m)
}
func SafeFileMap(m map[string]string) FileSystemFunc {
return func() (FileSystem, error) {
newm := make(map[string]string, len(m))
for new, old := range m {
new = strings.TrimSpace(new)
new = strings.TrimLeft(new, "/")
fi, err := os.Stat(old)
if err != nil {
return nil, errors.Wrapf(err, "%s is not a readable path", old)
}
_ = fi
newm[new] = old
}
return filemapFS(newm), nil
}
}
// filemapFS is the map based implementation of FileSystem
type filemapFS map[string]string
func (fs filemapFS) String() string {
return fmt.Sprintf("filemap(%v)", len(fs))
}
func (fs filemapFS) Close() error { return nil }
func (fs filemapFS) Open(p string) (ReadSeekCloser, error) {
b, ok := fs[filename(p)]
if !ok {
return nil, os.ErrNotExist
}
f, err := os.Open(b)
if err != nil {
return nil, err
}
fi, err := f.Stat()
if err != nil {
f.Close()
return nil, err
}
if fi.IsDir() {
f.Close()
return nil, fmt.Errorf("Open: %s is a directory", p)
}
return f, nil
}
func (fs filemapFS) Lstat(p string) (os.FileInfo, error) {
b, ok := fs[filename(p)]
if ok {
fi, err := os.Lstat(b)
if err != nil {
return nil, err
}
return osPathFI{renamedFileInfo(fi, b), b}, nil
}
ents, _ := fs.ReadDir(p)
if len(ents) > 0 {
return mapDirInfo(p), nil
}
return nil, os.ErrNotExist
}
func (fs filemapFS) Stat(p string) (os.FileInfo, error) {
return fs.Lstat(p)
}
func (fs filemapFS) ReadDir(p string) ([]os.FileInfo, error) {
p = pathpkg.Clean(p)
var ents []string
fim := make(map[string]os.FileInfo) // base -> fi
for fn, dst := range fs {
dir := slashdir(fn)
isFile := true
var lastBase string
for {
if dir == p {
base := lastBase
if isFile {
base = pathpkg.Base(fn)
}
if fim[base] == nil {
var fi os.FileInfo
if isFile {
var err error
fi, err = os.Stat(dst)
if err != nil {
return nil, err
}
fi = renamedFileInfo(fi, base)
} else {
fi = mapDirInfo(base)
}
ents = append(ents, base)
fim[base] = fi
}
}
if dir == "/" {
break
} else {
isFile = false
lastBase = pathpkg.Base(dir)
dir = pathpkg.Dir(dir)
}
}
}
if len(ents) == 0 {
return nil, os.ErrNotExist
}
sort.Strings(ents)
var list []os.FileInfo
for _, dir := range ents {
list = append(list, fim[dir])
}
return list, nil
}