@@ -21,6 +21,7 @@ import (
2121 "flag"
2222 "fmt"
2323 "io"
24+ "io/fs"
2425 "io/ioutil"
2526 "log"
2627 "os"
@@ -112,6 +113,53 @@ func readManifest(path string) ([]manifestEntry, error) {
112113 return entries , nil
113114}
114115
116+ func copySymlinkRecursively (src , dst string , writeFile func (src , dst string ) error , createDir func (dst string ) error ) error {
117+ target , err := os .Readlink (src )
118+ if err != nil {
119+ return err
120+ }
121+ if ! filepath .IsAbs (target ) {
122+ target = filepath .Join (filepath .Dir (src ), target )
123+ }
124+
125+ return copyRecursively (target , dst , writeFile , createDir )
126+ }
127+
128+ func copyRecursively (src , dst string , writeFile func (src , dst string ) error , createDir func (dst string ) error ) error {
129+ srcInfo , err := os .Stat (src )
130+ if err != nil {
131+ return err
132+ }
133+
134+ if srcInfo .Mode ().Type ()& fs .ModeDir != 0 {
135+ return filepath .WalkDir (src , func (path string , d os.DirEntry , err error ) error {
136+ if err != nil {
137+ return err
138+ }
139+ relDst , err := filepath .Rel (src , path )
140+ if err != nil {
141+ return err
142+ }
143+
144+ if d .Type ()& fs .ModeDir != 0 {
145+ return createDir (filepath .Join (dst , relDst ))
146+ }
147+
148+ if d .Type ()& fs .ModeSymlink != 0 {
149+ return copySymlinkRecursively (path , filepath .Join (dst , relDst ), writeFile , createDir )
150+ }
151+
152+ return writeFile (path , filepath .Join (dst , relDst ))
153+ })
154+ }
155+
156+ if srcInfo .Mode ().Type ()& fs .ModeSymlink != 0 {
157+ return copySymlinkRecursively (src , dst , writeFile , createDir )
158+ }
159+
160+ return writeFile (src , dst )
161+ }
162+
115163func archivePath (out string , manifest []manifestEntry ) (err error ) {
116164 outFile , err := os .Create (out )
117165 if err != nil {
@@ -124,12 +172,12 @@ func archivePath(out string, manifest []manifestEntry) (err error) {
124172 }()
125173 outZip := zip .NewWriter (outFile )
126174
127- for _ , entry := range manifest {
128- srcFile , err := os .Open (abs ( filepath . FromSlash ( entry . Src )) )
175+ writeFile := func ( src , dst string ) error {
176+ srcFile , err := os .Open (src )
129177 if err != nil {
130178 return err
131179 }
132- w , err := outZip .Create (entry . Dst )
180+ w , err := outZip .Create (dst )
133181 if err != nil {
134182 srcFile .Close ()
135183 return err
@@ -141,6 +189,19 @@ func archivePath(out string, manifest []manifestEntry) (err error) {
141189 if err := srcFile .Close (); err != nil {
142190 return err
143191 }
192+
193+ return nil
194+ }
195+ createDir := func (_ string ) error {
196+ // Directories are created automatically in ZIP files.
197+ return nil
198+ }
199+
200+ for _ , entry := range manifest {
201+ src := abs (filepath .FromSlash (entry .Src ))
202+ if err := copyRecursively (src , entry .Dst , writeFile , createDir ); err != nil {
203+ return err
204+ }
144205 }
145206
146207 if err := outZip .Close (); err != nil {
@@ -150,15 +211,14 @@ func archivePath(out string, manifest []manifestEntry) (err error) {
150211}
151212
152213func copyPath (out string , manifest []manifestEntry ) error {
153- if err := os .MkdirAll (out , 0777 ); err != nil {
214+ const dirMode = 0777
215+
216+ if err := os .MkdirAll (out , dirMode ); err != nil {
154217 return err
155218 }
156- for _ , entry := range manifest {
157- dst := abs (filepath .Join (out , filepath .FromSlash (entry .Dst )))
158- if err := os .MkdirAll (filepath .Dir (dst ), 0777 ); err != nil {
159- return err
160- }
161- srcFile , err := os .Open (abs (filepath .FromSlash (entry .Src )))
219+
220+ writeFile := func (src , dst string ) error {
221+ srcFile , err := os .Open (src )
162222 if err != nil {
163223 return err
164224 }
@@ -176,7 +236,25 @@ func copyPath(out string, manifest []manifestEntry) error {
176236 if err := dstFile .Close (); err != nil {
177237 return err
178238 }
239+
240+ return nil
179241 }
242+ createDir := func (dst string ) error {
243+ return os .Mkdir (dst , dirMode )
244+ }
245+
246+ for _ , entry := range manifest {
247+ dst := abs (filepath .Join (out , filepath .FromSlash (entry .Dst )))
248+ if err := os .MkdirAll (filepath .Dir (dst ), dirMode ); err != nil {
249+ return err
250+ }
251+
252+ src := abs (filepath .FromSlash (entry .Src ))
253+ if err := copyRecursively (src , dst , writeFile , createDir ); err != nil {
254+ return err
255+ }
256+ }
257+
180258 return nil
181259}
182260
0 commit comments