-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfile.go
175 lines (147 loc) · 3.3 KB
/
file.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
package fil
import (
"os"
"path/filepath"
"os/exec"
"errors"
"io"
"io/ioutil"
)
type Options struct {
Recursive bool
PreserveLinks bool
PreserveModTime bool
}
func ChmodR(name string, mode os.FileMode) error {
return filepath.Walk(name, func(path string, info os.FileInfo, err error) error {
if err == nil {
err = os.Chmod(path, mode)
}
return err
})
}
func ChownR(path string, uid, gid int) error {
return filepath.Walk(path, func(name string, info os.FileInfo, err error) error {
if err == nil {
err = os.Chown(name, uid, gid)
}
return err
})
}
func MkdirP(path string, perm os.FileMode) error {
return os.MkdirAll(path, perm)
}
func Mv(oldname, newname string) error {
return os.Rename(oldname, newname)
}
func Rm(name string) error {
return os.Remove(name)
}
func RmRF(path string) error {
return os.RemoveAll(path)
}
func Which(file string) (string, error) {
return exec.LookPath(file)
}
func Cp(src, dest string) error {
return CpWithOptions(src, dest, Options{PreserveLinks: true})
}
func CpR(source, dest string) error {
return CpWithOptions(source, dest, Options{Recursive: true, PreserveLinks: true})
}
func CpSymlinkContent(src, dest string) error {
return CpWithOptions(src, dest, Options{PreserveLinks: false})
}
func CpDirOnly(src, dest string) error {
fi, err := os.Lstat(src)
if err != nil {
return err
}
if !fi.IsDir() {
return errors.New("source is not a directory -- "+src)
}
if _, err := os.Open(dest); !os.IsNotExist(err) {
return errors.New("destination already exists -- "+dest)
}
if err := os.MkdirAll(dest, fi.Mode().Perm()); err != nil {
return err
}
return nil
}
func CpWithOptions(source, dest string, args Options) (err error) {
sourceInfo, err := os.Stat(source)
if err != nil {
return
}
if sourceInfo.IsDir() {
// Handle the dir case
if !args.Recursive {
return errors.New("source is a directory")
}
// ensure dest dir does not already exist
if _, err := os.Open(dest); !os.IsNotExist(err) {
return errors.New("destination already exists")
}
// create dest dir
if err = os.MkdirAll(dest, sourceInfo.Mode()); err != nil {
return
}
files, err := ioutil.ReadDir(source)
if err != nil {
return err
}
for _, file := range files {
if err = CpWithOptions(source+"/"+file.Name(), dest+"/"+file.Name(), args); err != nil {
return err
}
}
} else {
// Handle the file case
si, err := os.Lstat(source)
if err != nil {
return err
}
if args.PreserveLinks && !si.Mode().IsRegular() {
return cpSymlink(source, dest)
}
//open source
in, err := os.Open(source)
if err != nil {
return err
}
defer in.Close()
//create dest
out, err := os.Create(dest)
if err != nil {
return err
}
defer func() {
cerr := out.Close()
if err == nil {
err = cerr
}
}()
//copy to dest from source
if _, err = io.Copy(out, in); err != nil {
return err
}
if err = out.Chmod(si.Mode()); err != nil {
return err
}
if args.PreserveModTime {
if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
return err
}
}
//sync dest to disk
err = out.Sync()
}
return
}
func cpSymlink(src, dest string) error {
linkTarget, err := os.Readlink(src)
if err != nil {
return err
}
return os.Symlink(linkTarget, dest)
}