1
- // Package script is a library facilitating the creation of programs that resemble
2
- // bash scripts.
3
1
package script
4
2
5
3
import (
6
- "fmt"
7
- "io/ioutil"
8
4
"os"
9
5
"path"
10
6
"path/filepath"
7
+ "strings"
11
8
12
- "github.com/termie/go-shutil "
9
+ "github.com/spf13/afero "
13
10
)
14
11
15
12
// FileExists checks if a given filename exists (being a file).
16
13
func (c * Context ) FileExists (filename string ) bool {
17
14
filename = c .AbsPath (filename )
18
- fi , err := os .Stat (filename )
15
+ fi , err := c . fs .Stat (filename )
19
16
return ! os .IsNotExist (err ) && ! fi .IsDir ()
20
17
}
21
18
22
- // MustFileExist ensures if a given filename exists (being a file), panics otherwise.
23
- func (c * Context ) MustFileExist (filename string ) {
24
- if ! c .FileExists (filename ) {
25
- panic (fmt .Errorf ("File %s does not exist." , filename ))
26
- }
27
- }
28
-
29
19
// EnsureDirExists ensures a directory with the given name exists.
30
20
// This function panics if it is unable to find or create a directory as requested.
31
21
// TODO also check if permissions are less than requested and update if possible
32
- func (c * Context ) EnsureDirExists (dirname string , perm os.FileMode ) {
33
- if ! c .DirExists (dirname ) {
34
- err := os .MkdirAll (dirname , perm )
22
+ func (c * Context ) EnsureDirExists (dirname string , perm os.FileMode ) error {
23
+ fullPath := c .AbsPath (dirname )
24
+ if ! c .DirExists (fullPath ) {
25
+ err := c .fs .MkdirAll (fullPath , perm )
35
26
if err != nil {
36
- panic ( fmt . Errorf ( "Could not create directory at %s." , dirname ))
27
+ return err
37
28
}
38
29
}
30
+ return nil
39
31
}
40
32
41
33
// EnsurePathForFile guarantees the path for a given filename to exist.
42
34
// If the directory is not yet existing, it will be created using the permission
43
35
// mask given.
44
36
// TODO also check if permissions are less than requested and update if possible
45
- func (c * Context ) EnsurePathForFile (filename string , perm os.FileMode ) {
46
- c .EnsureDirExists (filepath .Dir (filename ), perm )
37
+ func (c * Context ) EnsurePathForFile (filename string , perm os.FileMode ) error {
38
+ return c .EnsureDirExists (filepath .Dir (filename ), perm )
47
39
}
48
40
49
41
// DirExists checks if a given filename exists (being a directory).
50
42
func (c * Context ) DirExists (path string ) bool {
51
43
path = c .AbsPath (path )
52
- fi , err := os .Stat (path )
44
+ fi , err := c . fs .Stat (path )
53
45
return ! os .IsNotExist (err ) && fi .IsDir ()
54
46
}
55
47
56
- // MustDirExist checks if a given filename exists (being a directory).
57
- func (c * Context ) MustDirExist (path string ) {
58
- if ! c .DirExists (path ) {
59
- panic (fmt .Errorf ("Directory %s does not exist." , path ))
60
- }
61
- }
62
-
63
- // MustGetTempFile guarantees to return a temporary file, panics otherwise
64
- func (c * Context ) MustGetTempFile () (tempFile * os.File ) {
65
- tempFile , err := ioutil .TempFile ("" , "" )
66
- if err != nil {
67
- panic (err )
68
- }
69
- return
48
+ // TempFile returns a temporary file and an error if one occurred
49
+ func (c * Context ) TempFile () (afero.File , error ) {
50
+ return afero .TempFile (c .fs , "" , "" )
70
51
}
71
52
72
- // MustGetTempDir guarantees to return a temporary directory, panics otherwise
73
- func (c * Context ) MustGetTempDir () (tempDir string ) {
74
- tempDir , err := ioutil .TempDir ("" , "" )
75
- if err != nil {
76
- panic (err )
77
- }
78
- return
53
+ // TempDir guarantees to return a temporary directory, panics otherwise
54
+ func (c * Context ) TempDir () (string , error ) {
55
+ return afero .TempDir (c .fs , "" , "" )
79
56
}
80
57
81
58
// AbsPath returns the absolute path of the path given. If the input path
82
- // is absolute, it is returned untouched. Otherwise the absolute path is
83
- // built relative to the current working directory of the Context.
59
+ // is absolute, it is returned untouched except for removing trailing path separators.
60
+ // Otherwise the absolute path is built relative to the current working directory of the Context.
61
+ // This function always returns a path *without* path separator at the end. See AbsPathSep for one that adds it.
84
62
func (c * Context ) AbsPath (filename string ) string {
63
+ filename = c .WithoutTrailingPathSep (filename )
85
64
absPath , err := filepath .Abs (filename )
86
65
if err != nil {
87
66
return filename
@@ -97,23 +76,46 @@ func (c *Context) AbsPath(filename string) string {
97
76
return filename
98
77
}
99
78
79
+ // AbsPathSep is a variant of AbsPath that always adds a trailing path separator
80
+ func (c * Context ) AbsPathSep (filename string ) string {
81
+ return c .WithTrailingPathSep (c .AbsPath (filename ))
82
+ }
83
+
84
+ // WithoutTrailingPathSep trims trailing path seps from a string
85
+ func (c * Context ) WithoutTrailingPathSep (input string ) string {
86
+ return strings .TrimRight (input , string (os .PathSeparator ))
87
+ }
88
+
89
+ // WithTrailingPathSep trims trailing path seps from a string
90
+ func (c * Context ) WithTrailingPathSep (input string ) string {
91
+ if strings .HasSuffix (input , string (os .PathSeparator )) {
92
+ return input
93
+ }
94
+ return input + string (os .PathSeparator )
95
+ }
96
+
100
97
// ResolveSymlinks resolve symlinks in a directory. All symlinked files are
101
98
// replaced with copies of the files they point to. Only one level symlinks
102
99
// are currently supported.
103
100
func (c * Context ) ResolveSymlinks (dir string ) error {
104
- err := filepath .Walk (dir , func (path string , info os.FileInfo , err error ) error {
101
+ var (
102
+ err error
103
+ linkTargetPath string
104
+ targetInfo os.FileInfo
105
+ )
106
+ err = filepath .Walk (dir , func (path string , info os.FileInfo , err error ) error {
105
107
// symlink?
106
108
if info .Mode ()& os .ModeSymlink == os .ModeSymlink {
107
109
// resolve
108
- linkTargetPath , err : = filepath .EvalSymlinks (path )
110
+ linkTargetPath , err = filepath .EvalSymlinks (path )
109
111
if err != nil {
110
112
panic (err )
111
113
}
112
- targetInfo , err := os .Stat (linkTargetPath )
114
+ targetInfo , err = c . fs .Stat (linkTargetPath )
113
115
if err != nil {
114
116
panic (err )
115
117
}
116
- os .Remove (path )
118
+ c . fs .Remove (path )
117
119
// directory?
118
120
if targetInfo .IsDir () {
119
121
c .CopyDir (linkTargetPath , path )
@@ -135,11 +137,11 @@ func (c *Context) MoveFile(from, to string) error {
135
137
to = c .AbsPath (to )
136
138
137
139
// work around "invalid cross-device link" for os.Rename
138
- err := shutil . CopyFile (from , to , true )
140
+ err := CopyFile (c . fs , from , to , true )
139
141
if err != nil {
140
142
return err
141
143
}
142
- err = os .Remove (from )
144
+ err = c . fs .Remove (from )
143
145
if err != nil {
144
146
return err
145
147
}
@@ -153,17 +155,15 @@ func (c *Context) MoveDir(from, to string) error {
153
155
to = c .AbsPath (to )
154
156
155
157
// work around "invalid cross-device link" for os.Rename
156
- options := & shutil.CopyTreeOptions {
157
- Symlinks : true ,
158
- Ignore : nil ,
159
- CopyFunction : shutil .Copy ,
160
- IgnoreDanglingSymlinks : false ,
158
+ options := & CopyTreeOptions {
159
+ Ignore : nil ,
160
+ CopyFunction : Copy ,
161
161
}
162
- err := shutil . CopyTree (from , to , options )
162
+ err := CopyTree (c . fs , from , to , options )
163
163
if err != nil {
164
164
return err
165
165
}
166
- err = os .RemoveAll (from )
166
+ err = c . fs .RemoveAll (from )
167
167
if err != nil {
168
168
return err
169
169
}
@@ -173,18 +173,16 @@ func (c *Context) MoveDir(from, to string) error {
173
173
// CopyFile copies a file. Cross-device copying is supported, so files
174
174
// can be copied from and to tmpfs mounts.
175
175
func (c * Context ) CopyFile (from , to string ) error {
176
- return shutil . CopyFile (from , to , true ) // don't follow symlinks
176
+ return CopyFile (c . fs , from , to , true ) // don't follow symlinks
177
177
}
178
178
179
179
// CopyDir copies a directory. Cross-device copying is supported, so directories
180
180
// can be copied from and to tmpfs mounts.
181
181
func (c * Context ) CopyDir (src , dst string ) error {
182
- options := & shutil.CopyTreeOptions {
183
- Symlinks : true ,
184
- Ignore : nil ,
185
- CopyFunction : shutil .Copy ,
186
- IgnoreDanglingSymlinks : false ,
182
+ options := & CopyTreeOptions {
183
+ Ignore : nil ,
184
+ CopyFunction : Copy ,
187
185
}
188
- err := shutil . CopyTree (src , dst , options )
186
+ err := CopyTree (c . fs , src , dst , options )
189
187
return err
190
188
}
0 commit comments