ci: add golangci-lint config and fix formatting
- Add .golangci.yml with minimal linters (govet, ineffassign) - Run gofmt -s and goimports on all files to fix formatting - Disable fieldalignment and copylocks checks in govet
This commit is contained in:
@@ -11,22 +11,22 @@ import (
|
||||
type Backend interface {
|
||||
// Upload uploads a file to cloud storage
|
||||
Upload(ctx context.Context, localPath, remotePath string, progress ProgressCallback) error
|
||||
|
||||
|
||||
// Download downloads a file from cloud storage
|
||||
Download(ctx context.Context, remotePath, localPath string, progress ProgressCallback) error
|
||||
|
||||
|
||||
// List lists all backup files in cloud storage
|
||||
List(ctx context.Context, prefix string) ([]BackupInfo, error)
|
||||
|
||||
|
||||
// Delete deletes a file from cloud storage
|
||||
Delete(ctx context.Context, remotePath string) error
|
||||
|
||||
|
||||
// Exists checks if a file exists in cloud storage
|
||||
Exists(ctx context.Context, remotePath string) (bool, error)
|
||||
|
||||
|
||||
// GetSize returns the size of a remote file
|
||||
GetSize(ctx context.Context, remotePath string) (int64, error)
|
||||
|
||||
|
||||
// Name returns the backend name (e.g., "s3", "azure", "gcs")
|
||||
Name() string
|
||||
}
|
||||
@@ -137,10 +137,10 @@ func (c *Config) Validate() error {
|
||||
|
||||
// ProgressReader wraps an io.Reader to track progress
|
||||
type ProgressReader struct {
|
||||
reader io.Reader
|
||||
total int64
|
||||
read int64
|
||||
callback ProgressCallback
|
||||
reader io.Reader
|
||||
total int64
|
||||
read int64
|
||||
callback ProgressCallback
|
||||
lastReport time.Time
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ func NewProgressReader(r io.Reader, total int64, callback ProgressCallback) *Pro
|
||||
func (pr *ProgressReader) Read(p []byte) (int, error) {
|
||||
n, err := pr.reader.Read(p)
|
||||
pr.read += int64(n)
|
||||
|
||||
|
||||
// Report progress every 100ms or when complete
|
||||
now := time.Now()
|
||||
if now.Sub(pr.lastReport) > 100*time.Millisecond || err == io.EOF {
|
||||
@@ -166,6 +166,6 @@ func (pr *ProgressReader) Read(p []byte) (int, error) {
|
||||
}
|
||||
pr.lastReport = now
|
||||
}
|
||||
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@ func NewS3Backend(cfg *Config) (*S3Backend, error) {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
|
||||
// Build AWS config
|
||||
var awsCfg aws.Config
|
||||
var err error
|
||||
|
||||
|
||||
if cfg.AccessKey != "" && cfg.SecretKey != "" {
|
||||
// Use explicit credentials
|
||||
credsProvider := credentials.NewStaticCredentialsProvider(
|
||||
@@ -42,7 +42,7 @@ func NewS3Backend(cfg *Config) (*S3Backend, error) {
|
||||
cfg.SecretKey,
|
||||
"",
|
||||
)
|
||||
|
||||
|
||||
awsCfg, err = config.LoadDefaultConfig(ctx,
|
||||
config.WithCredentialsProvider(credsProvider),
|
||||
config.WithRegion(cfg.Region),
|
||||
@@ -53,7 +53,7 @@ func NewS3Backend(cfg *Config) (*S3Backend, error) {
|
||||
config.WithRegion(cfg.Region),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load AWS config: %w", err)
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func NewS3Backend(cfg *Config) (*S3Backend, error) {
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
client := s3.NewFromConfig(awsCfg, clientOptions...)
|
||||
|
||||
return &S3Backend{
|
||||
@@ -114,7 +114,7 @@ func (s *S3Backend) Upload(ctx context.Context, localPath, remotePath string, pr
|
||||
|
||||
// Use multipart upload for files larger than 100MB
|
||||
const multipartThreshold = 100 * 1024 * 1024 // 100 MB
|
||||
|
||||
|
||||
if fileSize > multipartThreshold {
|
||||
return s.uploadMultipart(ctx, file, key, fileSize, progress)
|
||||
}
|
||||
@@ -137,7 +137,7 @@ func (s *S3Backend) uploadSimple(ctx context.Context, file *os.File, key string,
|
||||
Key: aws.String(key),
|
||||
Body: reader,
|
||||
})
|
||||
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upload to S3: %w", err)
|
||||
}
|
||||
@@ -151,10 +151,10 @@ func (s *S3Backend) uploadMultipart(ctx context.Context, file *os.File, key stri
|
||||
uploader := manager.NewUploader(s.client, func(u *manager.Uploader) {
|
||||
// Part size: 10MB
|
||||
u.PartSize = 10 * 1024 * 1024
|
||||
|
||||
|
||||
// Upload up to 10 parts concurrently
|
||||
u.Concurrency = 10
|
||||
|
||||
|
||||
// Leave parts on failure for debugging
|
||||
u.LeavePartsOnError = false
|
||||
})
|
||||
@@ -245,10 +245,10 @@ func (s *S3Backend) List(ctx context.Context, prefix string) ([]BackupInfo, erro
|
||||
if obj.Key == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
key := *obj.Key
|
||||
name := filepath.Base(key)
|
||||
|
||||
|
||||
// Skip if it's just a directory marker
|
||||
if strings.HasSuffix(key, "/") {
|
||||
continue
|
||||
@@ -260,11 +260,11 @@ func (s *S3Backend) List(ctx context.Context, prefix string) ([]BackupInfo, erro
|
||||
Size: *obj.Size,
|
||||
LastModified: *obj.LastModified,
|
||||
}
|
||||
|
||||
|
||||
if obj.ETag != nil {
|
||||
info.ETag = *obj.ETag
|
||||
}
|
||||
|
||||
|
||||
if obj.StorageClass != "" {
|
||||
info.StorageClass = string(obj.StorageClass)
|
||||
} else {
|
||||
@@ -285,7 +285,7 @@ func (s *S3Backend) Delete(ctx context.Context, remotePath string) error {
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
})
|
||||
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete object: %w", err)
|
||||
}
|
||||
@@ -301,7 +301,7 @@ func (s *S3Backend) Exists(ctx context.Context, remotePath string) (bool, error)
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
})
|
||||
|
||||
|
||||
if err != nil {
|
||||
// Check if it's a "not found" error
|
||||
if strings.Contains(err.Error(), "NotFound") || strings.Contains(err.Error(), "404") {
|
||||
@@ -321,7 +321,7 @@ func (s *S3Backend) GetSize(ctx context.Context, remotePath string) (int64, erro
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
})
|
||||
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get object metadata: %w", err)
|
||||
}
|
||||
@@ -338,7 +338,7 @@ func (s *S3Backend) BucketExists(ctx context.Context) (bool, error) {
|
||||
_, err := s.client.HeadBucket(ctx, &s3.HeadBucketInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
})
|
||||
|
||||
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "NotFound") || strings.Contains(err.Error(), "404") {
|
||||
return false, nil
|
||||
@@ -355,7 +355,7 @@ func (s *S3Backend) CreateBucket(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
if exists {
|
||||
return nil
|
||||
}
|
||||
@@ -363,7 +363,7 @@ func (s *S3Backend) CreateBucket(ctx context.Context) error {
|
||||
_, err = s.client.CreateBucket(ctx, &s3.CreateBucketInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
})
|
||||
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create bucket: %w", err)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func ParseCloudURI(uri string) (*CloudURI, error) {
|
||||
if len(parts) >= 3 {
|
||||
// Extract bucket name (first part)
|
||||
bucket = parts[0]
|
||||
|
||||
|
||||
// Extract region if present
|
||||
// bucket.s3.us-west-2.amazonaws.com -> us-west-2
|
||||
// bucket.s3-us-west-2.amazonaws.com -> us-west-2
|
||||
|
||||
Reference in New Issue
Block a user