@@ -11,6 +11,13 @@ import (
11
11
"path/filepath"
12
12
)
13
13
14
+ // List of arguments which can be passed to the CpWithArgs method
15
+ type CpArgs struct {
16
+ Recursive bool
17
+ PreserveLinks bool
18
+ PreserveTimestamps bool
19
+ }
20
+
14
21
// ChmodR is like `chmod -R`
15
22
func ChmodR (name string , mode os.FileMode ) error {
16
23
return filepath .Walk (name , func (path string , info os.FileInfo , err error ) error {
@@ -33,7 +40,7 @@ func ChownR(path string, uid, gid int) error {
33
40
34
41
// Cp is like `cp`
35
42
func Cp (src , dest string ) (err error ) {
36
- return cpFollowLinks (src , dest )
43
+ return CpWithArgs (src , dest , CpArgs {} )
37
44
}
38
45
39
46
func cpSymlink (src , dest string ) (err error ) {
@@ -47,133 +54,104 @@ func cpSymlink(src, dest string) (err error) {
47
54
}
48
55
49
56
func cpFollowLinks (src , dest string ) (err error ) {
50
- // get info on src
51
- si , err := os .Lstat (src )
52
- if err != nil {
53
- return
54
- }
55
-
56
- //open src
57
- in , err := os .Open (src )
58
- if err != nil {
59
- return
60
- }
61
- defer in .Close ()
62
-
63
- //create dest
64
- out , err := os .Create (dest )
65
- if err != nil {
66
- return
67
- }
68
- defer func () {
69
- cerr := out .Close ()
70
- if err == nil {
71
- err = cerr
72
- }
73
- }()
74
-
75
- //copy to dest from source
76
- if _ , err = io .Copy (out , in ); err != nil {
77
- return
78
- }
79
-
80
- if err = out .Chmod (si .Mode ()); err != nil {
81
- return
82
- }
83
-
84
- //sync dest to disk
85
- err = out .Sync ()
86
-
87
- return
57
+ return CpWithArgs (src , dest , CpArgs {})
88
58
}
89
59
90
60
func cpPreserveLinks (src , dest string ) (err error ) {
91
- // get info on src
92
- si , err := os .Lstat (src )
93
- if err != nil {
94
- return
95
- }
61
+ return CpWithArgs (src , dest , CpArgs {PreserveLinks : true })
62
+ }
96
63
97
- // handle symlinks
98
- if ! si .Mode ().IsRegular () {
99
- return cpSymlink (src , dest )
100
- }
64
+ /*
65
+ CpR is like `cp -R`
66
+ */
67
+ func CpR (source , dest string ) (err error ) {
68
+ return CpWithArgs (source , dest , CpArgs {Recursive : true })
69
+ }
101
70
102
- //open source
103
- in , err := os .Open ( src )
71
+ func CpWithArgs ( source , dest string , args CpArgs ) ( err error ) {
72
+ sourceInfo , err := os .Stat ( source )
104
73
if err != nil {
105
74
return
106
75
}
107
- defer in .Close ()
108
76
109
- //create dest
110
- out , err := os .Create (dest )
111
- if err != nil {
112
- return
113
- }
114
- defer func () {
115
- cerr := out .Close ()
116
- if err == nil {
117
- err = cerr
77
+ if sourceInfo .IsDir () {
78
+ // Handle the dir case
79
+ if ! args .Recursive {
80
+ return errors .New ("source is a directory" )
118
81
}
119
- }()
120
82
121
- //copy to dest from source
122
- if _ , err = io . Copy ( out , in ); err != nil {
123
- return
124
- }
83
+ // ensure dest dir does not already exist
84
+ if _ , err = os . Open ( dest ); ! os . IsNotExist ( err ) {
85
+ return errors . New ( "destination already exists" )
86
+ }
125
87
126
- if err = out .Chmod (si .Mode ()); err != nil {
127
- return
128
- }
88
+ // create dest dir
89
+ if err = os .MkdirAll (dest , sourceInfo .Mode ()); err != nil {
90
+ return
91
+ }
129
92
130
- //sync dest to disk
131
- err = out .Sync ()
93
+ files , err := ioutil .ReadDir (source )
94
+ if err != nil {
95
+ return err
96
+ }
132
97
133
- return
134
- }
98
+ for _ , file := range files {
99
+ sourceFilePath := fmt .Sprintf ("%s/%s" , source , file .Name ())
100
+ destFilePath := fmt .Sprintf ("%s/%s" , dest , file .Name ())
135
101
136
- /*
137
- CpR is like `cp -R`
138
- */
139
- func CpR (source , dest string ) (err error ) {
140
- // get properties of source dir
141
- sourceInfo , err := os .Stat (source )
142
- if err != nil {
143
- return
144
- }
102
+ if err = CpWithArgs (sourceFilePath , destFilePath , args ); err != nil {
103
+ return err
104
+ }
105
+ }
106
+ } else {
107
+ // Handle the file case
108
+ si , err := os .Lstat (source )
109
+ if err != nil {
110
+ return err
111
+ }
145
112
146
- if ! sourceInfo . IsDir () {
147
- return errors . New ( " source is not a directory" )
148
- }
113
+ if args . PreserveLinks && ! si . Mode (). IsRegular () {
114
+ return cpSymlink ( source , dest )
115
+ }
149
116
150
- // ensure dest dir does not already exist
151
- if _ , err = os .Open (dest ); ! os .IsNotExist (err ) {
152
- return errors .New ("destination already exists" )
153
- }
117
+ //open source
118
+ in , err := os .Open (source )
119
+ if err != nil {
120
+ return err
121
+ }
122
+ defer in .Close ()
154
123
155
- // create dest dir
156
- if err = os .MkdirAll (dest , sourceInfo .Mode ()); err != nil {
157
- return
158
- }
124
+ //create dest
125
+ out , err := os .Create (dest )
126
+ if err != nil {
127
+ return err
128
+ }
129
+ defer func () {
130
+ cerr := out .Close ()
131
+ if err == nil {
132
+ err = cerr
133
+ }
134
+ }()
159
135
160
- files , err := ioutil .ReadDir (source )
136
+ //copy to dest from source
137
+ if _ , err = io .Copy (out , in ); err != nil {
138
+ return err
139
+ }
161
140
162
- for _ , file := range files {
163
- sourceFilePath := fmt . Sprintf ( "%s/%s" , source , file . Name ())
164
- destFilePath := fmt . Sprintf ( "%s/%s" , dest , file . Name ())
141
+ if err = out . Chmod ( si . Mode ()); err != nil {
142
+ return err
143
+ }
165
144
166
- if file .IsDir () {
167
- if err = CpR (sourceFilePath , destFilePath ); err != nil {
168
- return
169
- }
170
- } else {
171
- if err = cpPreserveLinks (sourceFilePath , destFilePath ); err != nil {
172
- return
145
+ if args .PreserveTimestamps {
146
+ if err = os .Chtimes (dest , si .ModTime (), si .ModTime ()); err != nil {
147
+ return err
173
148
}
174
149
}
175
150
151
+ //sync dest to disk
152
+ err = out .Sync ()
176
153
}
154
+
177
155
return
178
156
}
179
157
0 commit comments