11package main
22
33import (
4+ "io"
45 "mime"
56 "os"
67 "path/filepath"
@@ -16,6 +17,7 @@ import (
1617 "github.com/aws/aws-sdk-go/service/sts"
1718 "github.com/mattn/go-zglob"
1819 log "github.com/sirupsen/logrus"
20+ "golang.org/x/sync/errgroup"
1921)
2022
2123// Plugin defines the S3 plugin parameters.
@@ -44,6 +46,9 @@ type Plugin struct {
4446 // sa-east-1
4547 Region string
4648
49+ // if true, plugin is set to download mode, which means `target` from the bucket will be downloaded
50+ Download bool
51+
4752 // Indicates the files ACL, which should be one
4853 // of the following:
4954 // private
@@ -135,6 +140,77 @@ func (p *Plugin) Exec() error {
135140 client = s3 .New (sess )
136141 }
137142
143+ if p .Download {
144+ targetDir := strings .TrimPrefix (filepath .ToSlash (p .Target ), "/" )
145+ log .WithFields (log.Fields {
146+ "bucket" : p .Bucket ,
147+ "dir" : targetDir ,
148+ }).Info ("Listing S3 directory" )
149+
150+ list , err := client .ListObjectsV2 (& s3.ListObjectsV2Input {
151+ Bucket : & p .Bucket ,
152+ Prefix : & targetDir ,
153+ })
154+ if err != nil {
155+ log .WithFields (log.Fields {
156+ "error" : err ,
157+ "bucket" : p .Bucket ,
158+ "dir" : targetDir ,
159+ }).Error ("Cannot list S3 directory" )
160+ return err
161+ }
162+
163+ g := errgroup.Group {}
164+
165+ for _ , item := range list .Contents {
166+ log .WithFields (log.Fields {
167+ "bucket" : p .Bucket ,
168+ "key" : * item .Key ,
169+ }).Info ("Getting S3 object" )
170+
171+ item := item
172+ g .Go (func () error {
173+ obj , err := client .GetObject (& s3.GetObjectInput {
174+ Bucket : & p .Bucket ,
175+ Key : item .Key ,
176+ })
177+ if err != nil {
178+ log .WithFields (log.Fields {
179+ "error" : err ,
180+ "bucket" : p .Bucket ,
181+ "key" : * item .Key ,
182+ }).Error ("Cannot get S3 object" )
183+ return err
184+ }
185+
186+ source := resolveSource (targetDir , * item .Key , p .StripPrefix )
187+
188+ f , err := os .Create (source )
189+ if err != nil {
190+ log .WithFields (log.Fields {
191+ "error" : err ,
192+ "file" : source ,
193+ }).Error ("Problem opening file for writing" )
194+ return err
195+ }
196+ defer f .Close ()
197+
198+ _ , err = io .Copy (f , obj .Body )
199+ if err != nil {
200+ log .WithFields (log.Fields {
201+ "error" : err ,
202+ "file" : source ,
203+ }).Error ("Failed to write file" )
204+ return err
205+ }
206+
207+ return nil
208+ })
209+ }
210+
211+ return g .Wait ()
212+ }
213+
138214 // find the bucket
139215 log .WithFields (log.Fields {
140216 "region" : p .Region ,
@@ -322,6 +398,11 @@ func resolveKey(target, srcPath, stripPrefix string) string {
322398 return key
323399}
324400
401+ func resolveSource (targetDir , target , stripPrefix string ) string {
402+ path := strings .TrimPrefix (strings .TrimPrefix (target , targetDir ), "/" )
403+ return stripPrefix + path
404+ }
405+
325406// checks if the source path is a dir
326407func isDir (source string , matches []string ) bool {
327408 stat , err := os .Stat (source )
0 commit comments