71 lines
1.9 KiB
Go
71 lines
1.9 KiB
Go
package upload
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
|
)
|
|
|
|
// PutObjectAPI is the subset of *s3.Client used here. Tests inject a fake.
|
|
type PutObjectAPI interface {
|
|
PutObject(ctx context.Context, in *s3.PutObjectInput, opts ...func(*s3.Options)) (*s3.PutObjectOutput, error)
|
|
}
|
|
|
|
// Opts configures a single upload.
|
|
type Opts struct {
|
|
Bucket string
|
|
Key string
|
|
FilePath string
|
|
}
|
|
|
|
// RenderKey substitutes {version} and {filename} placeholders.
|
|
func RenderKey(template, version, filename string) string {
|
|
r := strings.NewReplacer("{version}", version, "{filename}", filename)
|
|
return r.Replace(template)
|
|
}
|
|
|
|
// Upload PUTs FilePath at s3://Bucket/Key and returns the s3:// URL.
|
|
func Upload(ctx context.Context, c PutObjectAPI, o Opts) (string, error) {
|
|
f, err := os.Open(o.FilePath)
|
|
if err != nil {
|
|
return "", fmt.Errorf("open %s: %w", o.FilePath, err)
|
|
}
|
|
defer f.Close()
|
|
|
|
if _, err := c.PutObject(ctx, &s3.PutObjectInput{
|
|
Bucket: aws.String(o.Bucket),
|
|
Key: aws.String(o.Key),
|
|
Body: f,
|
|
}); err != nil {
|
|
return "", fmt.Errorf("s3 put: %w", err)
|
|
}
|
|
return fmt.Sprintf("s3://%s/%s", o.Bucket, o.Key), nil
|
|
}
|
|
|
|
// WriteFileForTest is exposed for use from this package's tests.
|
|
func WriteFileForTest(path string, b []byte) error {
|
|
return os.WriteFile(path, b, 0o600)
|
|
}
|
|
|
|
// NewClient builds an *s3.Client honouring an optional custom endpoint
|
|
// for S3-compatible storage.
|
|
func NewClient(ctx context.Context, region, endpointURL string) (*s3.Client, error) {
|
|
cfg, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(region))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("aws config: %w", err)
|
|
}
|
|
opts := []func(*s3.Options){}
|
|
if endpointURL != "" {
|
|
opts = append(opts, func(o *s3.Options) {
|
|
o.BaseEndpoint = aws.String(endpointURL)
|
|
o.UsePathStyle = true
|
|
})
|
|
}
|
|
return s3.NewFromConfig(cfg, opts...), nil
|
|
}
|