forked from gobuffalo/genny
-
Notifications
You must be signed in to change notification settings - Fork 0
/
disk.go
133 lines (116 loc) · 2.43 KB
/
disk.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
package genny
import (
"bytes"
"io"
"io/fs"
"os"
"runtime"
"sort"
"strings"
"sync"
"github.com/gobuffalo/packd"
)
// Disk is a virtual file system that works
// with both dry and wet runners. Perfect for seeding
// Files or non-destructively deleting files
type Disk struct {
Runner *Runner
files map[string]File
moot *sync.RWMutex
}
func (d *Disk) AddBox(box packd.Walker) error {
return box.Walk(func(path string, file packd.File) error {
d.Add(NewFile(path, file))
return nil
})
}
func (d *Disk) AddFS(fsys fs.FS) error {
return fs.WalkDir(fsys, ".", func(path string, dir fs.DirEntry, err error) error {
if err != nil {
return err
}
if dir.IsDir() {
return nil
}
file, err := fsys.Open(path)
if err != nil {
return err
}
d.Add(NewFile(path, file))
return nil
})
}
// Files returns a sorted list of all the files in the disk
func (d *Disk) Files() []File {
var files []File
for _, f := range d.files {
if s, ok := f.(io.Seeker); ok {
s.Seek(0, 0)
}
files = append(files, f)
}
sort.Slice(files, func(i, j int) bool {
return files[i].Name() < files[j].Name()
})
return files
}
func newDisk(r *Runner) *Disk {
return &Disk{
Runner: r,
files: map[string]File{},
moot: &sync.RWMutex{},
}
}
// Remove a file(s) from the virtual disk.
func (d *Disk) Remove(name string) {
d.moot.Lock()
defer d.moot.Unlock()
for f := range d.files {
if strings.HasPrefix(f, name) {
delete(d.files, f)
}
}
}
// Delete calls the Runner#Delete function
func (d *Disk) Delete(name string) error {
return d.Runner.Delete(name)
}
// Add file to the virtual disk
func (d *Disk) Add(f File) {
d.moot.Lock()
defer d.moot.Unlock()
d.files[f.Name()] = f
}
// Find a file from the virtual disk. If the file doesn't
// exist it will try to read the file from the physical disk.
func (d *Disk) Find(name string) (File, error) {
d.moot.RLock()
if f, ok := d.files[name]; ok {
if seek, ok := f.(io.Seeker); ok {
_, err := seek.Seek(0, 0)
if err != nil {
return nil, err
}
}
d.moot.RUnlock()
return f, nil
}
d.moot.RUnlock()
gf := NewFile(name, bytes.NewReader([]byte("")))
osname := name
if runtime.GOOS == "windows" {
osname = strings.Replace(osname, "/", "\\", -1)
}
f, err := os.Open(osname)
if err != nil {
return gf, err
}
defer f.Close()
bb := &bytes.Buffer{}
if _, err := io.Copy(bb, f); err != nil {
return gf, err
}
gf = NewFile(name, bb)
d.Add(gf)
return gf, nil
}