11package main
22
33import (
4+ "context"
45 "crypto/md5"
6+ "errors"
57 "fmt"
68 "io"
79 "mime"
810 "os"
911 "path/filepath"
10- "strings"
1112 "time"
1213
13- "github.com/aws/aws-sdk-go/aws"
14- "github.com/aws/aws-sdk-go/aws/awserr"
15- "github.com/aws/aws-sdk-go/aws/credentials"
16- "github.com/aws/aws-sdk-go/aws/session"
17- "github.com/aws/aws-sdk-go/service/cloudfront"
18- "github.com/aws/aws-sdk-go/service/s3"
14+ "github.com/aws/aws-sdk-go-v2/aws"
15+ "github.com/aws/aws-sdk-go-v2/config"
16+ "github.com/aws/aws-sdk-go-v2/credentials"
17+ "github.com/aws/aws-sdk-go-v2/service/cloudfront"
18+ cftypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
19+ "github.com/aws/aws-sdk-go-v2/service/s3"
20+ s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
21+ "github.com/aws/smithy-go"
1922 "github.com/ryanuber/go-glob"
2023)
2124
2225type AWS struct {
23- client * s3.S3
24- cfClient * cloudfront.CloudFront
26+ client * s3.Client
27+ cfClient * cloudfront.Client
2528 remote []string
2629 local []string
2730 plugin * Plugin
2831}
2932
3033func NewAWS (p * Plugin ) AWS {
34+ ctx := context .Background ()
3135
32- sessCfg := & aws.Config {
33- S3ForcePathStyle : aws .Bool (p .PathStyle ),
34- Region : aws .String (p .Region ),
36+ optFns := []func (* config.LoadOptions ) error {
37+ config .WithRegion (p .Region ),
3538 }
3639
37- if p .Endpoint != "" {
38- sessCfg .Endpoint = & p .Endpoint
39- sessCfg .DisableSSL = aws .Bool (strings .HasPrefix (p .Endpoint , "http://" ))
40+ if p .Key != "" && p .Secret != "" {
41+ optFns = append (optFns , config .WithCredentialsProvider (
42+ credentials .NewStaticCredentialsProvider (p .Key , p .Secret , "" ),
43+ ))
4044 }
4145
42- // allowing to use the instance role or provide a key and secret
43- if p . Key != "" && p . Secret != "" {
44- sessCfg . Credentials = credentials . NewStaticCredentials ( p . Key , p . Secret , "" )
46+ cfg , err := config . LoadDefaultConfig ( ctx , optFns ... )
47+ if err != nil {
48+ panic ( fmt . Sprintf ( "unable to load AWS config: %v" , err ) )
4549 }
4650
47- sess , _ := session .NewSession (sessCfg )
51+ s3Opts := []func (* s3.Options ){}
52+ if p .Endpoint != "" {
53+ s3Opts = append (s3Opts , func (o * s3.Options ) {
54+ o .BaseEndpoint = aws .String (p .Endpoint )
55+ o .UsePathStyle = p .PathStyle
56+ })
57+ } else if p .PathStyle {
58+ s3Opts = append (s3Opts , func (o * s3.Options ) {
59+ o .UsePathStyle = true
60+ })
61+ }
4862
49- c := s3 .New ( sess )
50- cf := cloudfront .New ( sess )
63+ c := s3 .NewFromConfig ( cfg , s3Opts ... )
64+ cf := cloudfront .NewFromConfig ( cfg )
5165 r := make ([]string , 1 )
5266 l := make ([]string , 1 )
5367
5468 return AWS {c , cf , r , l , p }
5569}
5670
5771func (a * AWS ) Upload (local , remote string ) error {
72+ ctx := context .Background ()
5873 p := a .plugin
5974 if local == "" {
6075 return nil
@@ -109,29 +124,67 @@ func (a *AWS) Upload(local, remote string) error {
109124 }
110125 }
111126
112- metadata := map [string ]* string {}
127+ metadata := map [string ]string {}
113128 for pattern := range p .Metadata {
114129 if match := glob .Glob (pattern , local ); match {
115130 for k , v := range p .Metadata [pattern ] {
116- metadata [k ] = aws . String ( v )
131+ metadata [k ] = v
117132 }
118133 break
119134 }
120135 }
121136
122- head , err := a .client .HeadObject (& s3.HeadObjectInput {
137+ head , err := a .client .HeadObject (ctx , & s3.HeadObjectInput {
123138 Bucket : aws .String (p .Bucket ),
124139 Key : aws .String (remote ),
125140 })
126- if err != nil && err .(awserr.Error ).Code () != "404" {
141+ if err != nil {
142+ var apiErr smithy.APIError
143+ isNotFound := false
144+ if ok := errors .As (err , & apiErr ); ok {
145+ if apiErr .ErrorCode () == "404" || apiErr .ErrorCode () == "NotFound" {
146+ isNotFound = true
147+ }
148+ }
149+ var nsb * s3types.NoSuchKey
150+ if errors .As (err , & nsb ) {
151+ isNotFound = true
152+ }
153+
154+ if ! isNotFound {
155+ debug ("\" %s\" not found in bucket, uploading with Content-Type \" %s\" and permissions \" %s\" " , local , contentType , access )
156+ var putObject = & s3.PutObjectInput {
157+ Bucket : aws .String (p .Bucket ),
158+ Key : aws .String (remote ),
159+ Body : file ,
160+ ContentType : aws .String (contentType ),
161+ ACL : s3types .ObjectCannedACL (access ),
162+ Metadata : metadata ,
163+ }
164+
165+ if len (cacheControl ) > 0 {
166+ putObject .CacheControl = aws .String (cacheControl )
167+ }
168+
169+ if len (contentEncoding ) > 0 {
170+ putObject .ContentEncoding = aws .String (contentEncoding )
171+ }
172+
173+ if a .plugin .DryRun {
174+ return nil
175+ }
176+
177+ _ , err = a .client .PutObject (ctx , putObject )
178+ return err
179+ }
127180
128181 debug ("\" %s\" not found in bucket, uploading with Content-Type \" %s\" and permissions \" %s\" " , local , contentType , access )
129182 var putObject = & s3.PutObjectInput {
130183 Bucket : aws .String (p .Bucket ),
131184 Key : aws .String (remote ),
132185 Body : file ,
133186 ContentType : aws .String (contentType ),
134- ACL : aws . String (access ),
187+ ACL : s3types . ObjectCannedACL (access ),
135188 Metadata : metadata ,
136189 }
137190
@@ -143,12 +196,11 @@ func (a *AWS) Upload(local, remote string) error {
143196 putObject .ContentEncoding = aws .String (contentEncoding )
144197 }
145198
146- // skip upload during dry run
147199 if a .plugin .DryRun {
148200 return nil
149201 }
150202
151- _ , err = a .client .PutObject (putObject )
203+ _ , err = a .client .PutObject (ctx , putObject )
152204 return err
153205 }
154206
@@ -197,7 +249,7 @@ func (a *AWS) Upload(local, remote string) error {
197249 if ! shouldCopy && len (metadata ) > 0 {
198250 for k , v := range metadata {
199251 if hv , ok := head .Metadata [k ]; ok {
200- if * v != * hv {
252+ if v != hv {
201253 debug ("Metadata values have changed for %s" , local )
202254 shouldCopy = true
203255 break
@@ -208,7 +260,7 @@ func (a *AWS) Upload(local, remote string) error {
208260
209261 if ! shouldCopy {
210262 debug ("Retrieving ACL for \" %s\" " , local )
211- grant , err := a .client .GetObjectAcl (& s3.GetObjectAclInput {
263+ grant , err := a .client .GetObjectAcl (ctx , & s3.GetObjectAclInput {
212264 Bucket : aws .String (p .Bucket ),
213265 Key : aws .String (remote ),
214266 })
@@ -218,12 +270,12 @@ func (a *AWS) Upload(local, remote string) error {
218270
219271 previousAccess := "private"
220272 for _ , g := range grant .Grants {
221- gt := * g .Grantee
273+ gt := g .Grantee
222274 if gt .URI != nil {
223275 if * gt .URI == "http://acs.amazonaws.com/groups/global/AllUsers" {
224- if * g .Permission == "READ" {
276+ if g .Permission == s3types . PermissionRead {
225277 previousAccess = "public-read"
226- } else if * g .Permission == "WRITE" {
278+ } else if g .Permission == s3types . PermissionWrite {
227279 previousAccess = "public-read-write"
228280 }
229281 }
@@ -246,10 +298,10 @@ func (a *AWS) Upload(local, remote string) error {
246298 Bucket : aws .String (p .Bucket ),
247299 Key : aws .String (remote ),
248300 CopySource : aws .String (fmt .Sprintf ("%s/%s" , p .Bucket , remote )),
249- ACL : aws . String (access ),
301+ ACL : s3types . ObjectCannedACL (access ),
250302 ContentType : aws .String (contentType ),
251303 Metadata : metadata ,
252- MetadataDirective : aws . String ( "REPLACE" ) ,
304+ MetadataDirective : s3types . MetadataDirectiveReplace ,
253305 }
254306
255307 if len (cacheControl ) > 0 {
@@ -260,12 +312,11 @@ func (a *AWS) Upload(local, remote string) error {
260312 copyObject .ContentEncoding = aws .String (contentEncoding )
261313 }
262314
263- // skip update if dry run
264315 if a .plugin .DryRun {
265316 return nil
266317 }
267318
268- _ , err = a .client .CopyObject (copyObject )
319+ _ , err = a .client .CopyObject (ctx , copyObject )
269320 return err
270321 } else {
271322 _ , err = file .Seek (0 , 0 )
@@ -279,7 +330,7 @@ func (a *AWS) Upload(local, remote string) error {
279330 Key : aws .String (remote ),
280331 Body : file ,
281332 ContentType : aws .String (contentType ),
282- ACL : aws . String (access ),
333+ ACL : s3types . ObjectCannedACL (access ),
283334 Metadata : metadata ,
284335 }
285336
@@ -291,52 +342,54 @@ func (a *AWS) Upload(local, remote string) error {
291342 putObject .ContentEncoding = aws .String (contentEncoding )
292343 }
293344
294- // skip upload if dry run
295345 if a .plugin .DryRun {
296346 return nil
297347 }
298348
299- _ , err = a .client .PutObject (putObject )
349+ _ , err = a .client .PutObject (ctx , putObject )
300350 return err
301351 }
302352}
303353
304354func (a * AWS ) Redirect (path , location string ) error {
355+ ctx := context .Background ()
305356 p := a .plugin
306357 debug ("Adding redirect from \" %s\" to \" %s\" " , path , location )
307358
308359 if a .plugin .DryRun {
309360 return nil
310361 }
311362
312- _ , err := a .client .PutObject (& s3.PutObjectInput {
363+ _ , err := a .client .PutObject (ctx , & s3.PutObjectInput {
313364 Bucket : aws .String (p .Bucket ),
314365 Key : aws .String (path ),
315- ACL : aws . String ( "public-read" ) ,
366+ ACL : s3types . ObjectCannedACLPublicRead ,
316367 WebsiteRedirectLocation : aws .String (location ),
317368 })
318369 return err
319370}
320371
321372func (a * AWS ) Delete (remote string ) error {
373+ ctx := context .Background ()
322374 p := a .plugin
323375 debug ("Removing remote file \" %s\" " , remote )
324376
325377 if a .plugin .DryRun {
326378 return nil
327379 }
328380
329- _ , err := a .client .DeleteObject (& s3.DeleteObjectInput {
381+ _ , err := a .client .DeleteObject (ctx , & s3.DeleteObjectInput {
330382 Bucket : aws .String (p .Bucket ),
331383 Key : aws .String (remote ),
332384 })
333385 return err
334386}
335387
336388func (a * AWS ) List (path string ) ([]string , error ) {
389+ ctx := context .Background ()
337390 p := a .plugin
338391 remote := make ([]string , 1 )
339- resp , err := a .client .ListObjects (& s3.ListObjectsInput {
392+ resp , err := a .client .ListObjects (ctx , & s3.ListObjectsInput {
340393 Bucket : aws .String (p .Bucket ),
341394 Prefix : aws .String (path ),
342395 })
@@ -348,8 +401,8 @@ func (a *AWS) List(path string) ([]string, error) {
348401 remote = append (remote , * item .Key )
349402 }
350403
351- for * resp .IsTruncated {
352- resp , err = a .client .ListObjects (& s3.ListObjectsInput {
404+ for aws . ToBool ( resp .IsTruncated ) {
405+ resp , err = a .client .ListObjects (ctx , & s3.ListObjectsInput {
353406 Bucket : aws .String (p .Bucket ),
354407 Prefix : aws .String (path ),
355408 Marker : aws .String (remote [len (remote )- 1 ]),
@@ -368,16 +421,17 @@ func (a *AWS) List(path string) ([]string, error) {
368421}
369422
370423func (a * AWS ) Invalidate (invalidatePath string ) error {
424+ ctx := context .Background ()
371425 p := a .plugin
372426 debug ("Invalidating \" %s\" " , invalidatePath )
373- _ , err := a .cfClient .CreateInvalidation (& cloudfront.CreateInvalidationInput {
427+ _ , err := a .cfClient .CreateInvalidation (ctx , & cloudfront.CreateInvalidationInput {
374428 DistributionId : aws .String (p .CloudFrontDistribution ),
375- InvalidationBatch : & cloudfront .InvalidationBatch {
429+ InvalidationBatch : & cftypes .InvalidationBatch {
376430 CallerReference : aws .String (time .Now ().Format (time .RFC3339Nano )),
377- Paths : & cloudfront .Paths {
378- Quantity : aws .Int64 (1 ),
379- Items : []* string {
380- aws . String ( invalidatePath ) ,
431+ Paths : & cftypes .Paths {
432+ Quantity : aws .Int32 (1 ),
433+ Items : []string {
434+ invalidatePath ,
381435 },
382436 },
383437 },
0 commit comments