-
Notifications
You must be signed in to change notification settings - Fork 0
/
local.go
141 lines (119 loc) · 3.11 KB
/
local.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
package fsys
import (
"io"
"os"
"strings"
"github.com/pkg/errors"
)
const mkdirAllMode = 0755
type LocalFileSystem struct{}
// NewLocalFileSystem yields a local disk filesystem.
func NewLocalFileSystem() LocalFileSystem {
return LocalFileSystem{}
}
// Create takes a path, creates the file and then returns a File back that
// can be used. This returns an error if the file can not be created in
// some way.
func (LocalFileSystem) Create(path string) (File, error) {
f, err := os.Create(path)
return LocalFile{
File: f,
Reader: f,
Closer: f,
}, err
}
// Open takes a path, opens a potential file and then returns a File if
// that file exists, otherwise it returns an error if the file wasn't found.
func (fs LocalFileSystem) Open(path string) (File, error) {
f, err := os.Open(path)
return fs.open(f, err)
}
// OpenFile takes a path, opens a potential file and then returns a File if
// that file exists, otherwise it returns an error if the file wasn't found.
func (fs LocalFileSystem) OpenFile(path string, flag int, perm os.FileMode) (File, error) {
f, err := os.OpenFile(path, flag, perm)
return fs.open(f, err)
}
// Exists takes a path and checks to see if the potential file exists or
// not.
// Note: If there is an error trying to read that file, it will return false
// even if the file already exists.
func (LocalFileSystem) Exists(path string) bool {
_, err := os.Stat(path)
return !os.IsNotExist(err)
}
// Remove takes a path, removes a potential file, if no file doesn't exist it
// will return not found.
func (LocalFileSystem) Remove(path string) error {
return os.Remove(path)
}
func (fs LocalFileSystem) open(f *os.File, err error) (LocalFile, error) {
if err != nil {
if err == os.ErrNotExist {
return LocalFile{}, errors.Wrap(err, "not found")
}
return LocalFile{}, errors.WithStack(err)
}
return LocalFile{
File: f,
Reader: f,
Closer: f,
}, nil
}
// LocalFile is an abstraction for reading, writing and also closing a file.
type LocalFile struct {
*os.File
io.Reader
io.Closer
}
func (f LocalFile) Read(p []byte) (int, error) {
return f.Reader.Read(p)
}
func (f LocalFile) Close() error {
return f.Closer.Close()
}
// Size returns the size of the file
func (f LocalFile) Size() int64 {
fi, err := f.File.Stat()
if err != nil {
return -1
}
return fi.Size()
}
type deletingReleaser struct {
path string
r Releaser
}
func (dr deletingReleaser) Release() error {
// Remove before Release should be safe, and prevents a race.
if err := os.Remove(dr.path); err != nil {
return err
}
return dr.r.Release()
}
// multiCloser closes all underlying io.Closers.
// If an error is encountered, closings continue.
type multiCloser []io.Closer
func (c multiCloser) Close() error {
var errs []error
for _, closer := range c {
if closer == nil {
continue
}
if err := closer.Close(); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return multiCloseError(errs)
}
return nil
}
type multiCloseError []error
func (e multiCloseError) Error() string {
a := make([]string, len(e))
for i, err := range e {
a[i] = err.Error()
}
return strings.Join(a, "; ")
}