Skip to content

Commit bb232c8

Browse files
committed
Improved readability and maintainability
1 parent 187849f commit bb232c8

File tree

2 files changed

+115
-153
lines changed

2 files changed

+115
-153
lines changed

cmd/src/snapshot_upload.go

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66
"fmt"
77
"io"
88
"os"
9-
"path"
109
"path/filepath"
10+
"slices"
1111
"strings"
1212

1313
"cloud.google.com/go/storage"
@@ -19,9 +19,20 @@ import (
1919
"github.com/sourcegraph/src-cli/internal/pgdump"
2020
)
2121

22+
// Package-level variables
2223
const srcSnapshotDir = "./src-snapshot"
2324

24-
var srcSnapshotSummaryPath = path.Join(srcSnapshotDir, "summary.json")
25+
// summaryFile on its own, as it gets handled a little differently
26+
const summaryFile = "summary.json"
27+
var srcSnapshotSummaryPath = filepath.Join(srcSnapshotDir, summaryFile)
28+
29+
// listOfValidFiles defines the valid snapshot filenames (with extensions) that can be uploaded
30+
var listOfValidFiles = []string{
31+
"codeinsights.sql",
32+
"codeintel.sql",
33+
"pgsql.sql",
34+
summaryFile,
35+
}
2536

2637
// Define types
2738
type uploadArgs struct {
@@ -31,13 +42,14 @@ type uploadArgs struct {
3142
filesToUpload []string
3243
}
3344

45+
// Google Cloud Storage upload client
3446
type gcsClient struct {
3547
ctx context.Context
3648
out *output.Output
3749
storageClient *storage.Client
3850
}
3951

40-
// uploadFile represents a file registered for upload
52+
// uploadFile represents a file opened for upload
4153
type uploadFile struct {
4254
file *os.File
4355
stat os.FileInfo
@@ -46,7 +58,7 @@ type uploadFile struct {
4658

4759

4860
func init() {
49-
usage := `'src snapshot upload' uploads instance snapshot contents generated by 'src snapshot databases' and 'src snapshot summary' to the designated bucket.
61+
usage := fmt.Sprintf(`'src snapshot upload' uploads instance snapshot contents generated by 'src snapshot databases' and 'src snapshot summary' to the designated bucket.
5062
5163
USAGE
5264
src snapshot upload -bucket=$MIGRATION_BUCKET_NAME -credentials=./migration_private_key.json [-file=$FILE]
@@ -55,15 +67,15 @@ BUCKET
5567
In general, a Google Cloud Storage bucket and relevant credentials will be provided by Sourcegraph when using this functionality to share a snapshot with Sourcegraph.
5668
5769
FILE
58-
Optional: Specify files to upload as a comma-delimited list. Valid values: summary, primary, codeintel, codeinsights. Default: All valid values.
59-
Examples: -file=summary,primary or -file=codeintel
60-
`
70+
Optional: Specify files to upload as a comma-delimited list (with file extensions). Valid values: %s. Default: All files.
71+
Examples: -file=summary.json,pgsql.sql or -file=codeintel.sql
72+
`, strings.Join(listOfValidFiles, ", "))
6173

6274
flagSet := flag.NewFlagSet("upload", flag.ExitOnError)
6375
bucketName := flagSet.String("bucket", "", "destination Cloud Storage bucket name")
6476
credentialsPath := flagSet.String("credentials", "", "JSON credentials file for Google Cloud service account")
77+
fileFilter := flagSet.String("file", strings.Join(listOfValidFiles, ","), "comma-delimited list of files to upload")
6578
filterSQL := flagSet.Bool("filter-sql", true, "filter incompatible SQL statements from database dumps for import to Google Cloud SQL")
66-
fileFilter := flagSet.String("file", "summary,primary,codeintel,codeinsights", "comma-delimited list of files to upload")
6779

6880
// Register this command with the parent 'src snapshot' command.
6981
// The parent snapshot.go command runs all registered subcommands via snapshotCommands.run().
@@ -76,14 +88,14 @@ FILE
7688
})
7789
}
7890

79-
// Helper function to keep init() succinct
91+
// Handler function to keep init() succinct
8092
func snapshotUploadHandler(flagSet *flag.FlagSet, bucketName, credentialsPath *string, filterSQL *bool, fileFilter *string) func([]string) error {
8193
return func(args []string) error {
8294
if err := flagSet.Parse(args); err != nil {
8395
return err
8496
}
8597

86-
// Validate and parse inputs
98+
// Validate and parse inputs into an uploadArgs-type object
8799
uploadArgs, err := validateUploadInputs(*bucketName, *credentialsPath, *fileFilter, *filterSQL)
88100
if err != nil {
89101
return err
@@ -131,43 +143,41 @@ func validateUploadInputs(bucketName, credentialsPath, fileFilter string, filter
131143
// Parse the --file arg values, and return a list of strings of the files to upload
132144
func parseFileFilter(fileFilter string) ([]string, error) {
133145

134-
validFiles := map[string]bool{
135-
"summary": true,
136-
"primary": true,
137-
"codeintel": true,
138-
"codeinsights": true,
139-
}
140-
146+
// Default: all files
141147
if fileFilter == "" {
142-
// Default: all files
143-
return []string{"summary", "primary", "codeintel", "codeinsights"}, nil
148+
return listOfValidFiles, nil
144149
}
145150

146-
// Parse comma-delimited list
147151
var filesToUpload []string
148-
parts := strings.Split(fileFilter, ",")
149-
for _, part := range parts {
150152

151-
// Normalize: trim spaces and strip file extensions
152-
normalized := strings.TrimSpace(part)
153-
normalized = strings.TrimSuffix(normalized, ".json")
154-
normalized = strings.TrimSuffix(normalized, ".sql")
153+
// Parse comma-delimited list
154+
for _, part := range strings.Split(fileFilter, ",") {
155155

156-
// Validate
157-
if !validFiles[normalized] {
158-
return nil, errors.Newf("invalid -file value %q. Valid values: summary[.json], primary[.sql], codeintel[.sql], codeinsights[.sql]", part)
156+
// Trim whitespace
157+
filename := strings.TrimSpace(part)
158+
159+
// Validate against list of valid files
160+
if !slices.Contains(listOfValidFiles, filename) {
161+
return nil, errors.Newf("invalid -file value %q. Valid values: %s", part, strings.Join(listOfValidFiles, ", "))
159162
}
160163

161-
filesToUpload = append(filesToUpload, normalized)
164+
filesToUpload = append(filesToUpload, filename)
162165
}
163166

167+
// Sort files alphabetically for consistent ordering
168+
slices.Sort(filesToUpload)
169+
170+
// Remove duplicates (works on sorted slices by removing adjacent duplicates)
171+
filesToUpload = slices.Compact(filesToUpload)
172+
164173
return filesToUpload, nil
165174
}
166175

167176
func createGcsClient(flagSet *flag.FlagSet, credentialsPath string) (*gcsClient, error) {
168177

169-
out := output.NewOutput(flagSet.Output(), output.OutputOpts{Verbose: *verbose})
170178
ctx := context.Background()
179+
out := output.NewOutput(flagSet.Output(), output.OutputOpts{Verbose: *verbose})
180+
171181
// https://pkg.go.dev/cloud.google.com/go/storage#section-readme
172182
client, err := storage.NewClient(ctx, option.WithCredentialsFile(credentialsPath))
173183

@@ -186,22 +196,25 @@ func createGcsClient(flagSet *flag.FlagSet, credentialsPath string) (*gcsClient,
186196
// Returns arrays of uploadFile and progress bars (aligned by index).
187197
func openFilesAndCreateProgressBars(args *uploadArgs) ([]uploadFile, []output.ProgressBar, error) {
188198
var (
189-
openedFiles []uploadFile // Files opened from disk, ready for upload (aligned with progressBars)
199+
openedFiles []uploadFile // Files opened from disk, ready for upload (aligned with progressBars)
190200
progressBars []output.ProgressBar // Progress bars for UI (aligned with openedFiles)
191201
)
192202

193203
// addFile opens a file from disk and registers it for upload.
194204
// It adds the file to the openedFiles array and creates a corresponding progress bar.
195205
// For database dumps (!isSummary), SQL filtering is enabled based on args.filterSQL.
196-
addFile := func(filePath string, isSummary bool) error {
206+
addFile := func(filePath string) error {
207+
208+
isSummary := strings.HasSuffix(filePath, summaryFile)
197209

198210
// Open the file
199211
openFile, err := os.Open(filePath)
212+
200213
if err != nil {
201214
if isSummary {
202-
return errors.Wrap(err, "failed to open snapshot summary - generate one with 'src snapshot summary'")
215+
return errors.Wrap(err, fmt.Sprintf("failed to open snapshot summary %s - Please generate it with 'src snapshot summary'", filePath))
203216
}
204-
return errors.Wrap(err, "failed to open database dump - generate one with 'src snapshot databases'")
217+
return errors.Wrap(err, fmt.Sprintf("failed to open database dump %s - Please generate them with 'src snapshot databases'", filePath))
205218
}
206219

207220
// Get file metadata (name, size)
@@ -228,17 +241,12 @@ func openFilesAndCreateProgressBars(args *uploadArgs) ([]uploadFile, []output.Pr
228241
// Open files based on user's selection (via --file arg)
229242
// Iterate through the user's selected files and open each one
230243
for _, selectedFile := range args.filesToUpload {
231-
if selectedFile == "summary" {
232-
// Open summary.json
233-
if err := addFile(srcSnapshotSummaryPath, true); err != nil {
234-
return nil, nil, err
235-
}
236-
} else {
237-
// Open database dump file (primary.sql, codeintel.sql, or codeinsights.sql)
238-
dbFilePath := filepath.Join(srcSnapshotDir, selectedFile+".sql")
239-
if err := addFile(dbFilePath, false); err != nil {
240-
return nil, nil, err
241-
}
244+
245+
// Construct full file path
246+
filePath := filepath.Join(srcSnapshotDir, selectedFile)
247+
248+
if err := addFile(filePath); err != nil {
249+
return nil, nil, err
242250
}
243251
}
244252

@@ -248,6 +256,7 @@ func openFilesAndCreateProgressBars(args *uploadArgs) ([]uploadFile, []output.Pr
248256
// uploadFilesToBucket uploads the prepared files to Google Cloud Storage bucket.
249257
// Uploads are performed in parallel with progress tracking.
250258
func uploadFilesToBucket(client *gcsClient, args *uploadArgs, openedFiles []uploadFile, progressBars []output.ProgressBar) error {
259+
251260
// Start uploads with progress tracking
252261
progress := client.out.Progress(progressBars, nil)
253262
progress.WriteLine(output.Emoji(output.EmojiHourglass, "Starting uploads..."))
@@ -256,8 +265,10 @@ func uploadFilesToBucket(client *gcsClient, args *uploadArgs, openedFiles []uplo
256265

257266
// Upload each file in parallel
258267
for fileIndex, openedFile := range openedFiles {
268+
259269
fileIndex := fileIndex
260270
openedFile := openedFile
271+
261272
uploadPool.Go(func(ctx context.Context) error {
262273
progressFn := func(bytesWritten int64) { progress.SetValue(fileIndex, float64(bytesWritten)) }
263274

@@ -273,11 +284,11 @@ func uploadFilesToBucket(client *gcsClient, args *uploadArgs, openedFiles []uplo
273284
errs := uploadPool.Wait()
274285
progress.Complete()
275286
if errs != nil {
276-
client.out.WriteLine(output.Line(output.EmojiFailure, output.StyleFailure, "Some snapshot contents failed to upload."))
287+
client.out.WriteLine(output.Line(output.EmojiFailure, output.StyleFailure, "Some file(s) failed to upload."))
277288
return errs
278289
}
279290

280-
client.out.WriteLine(output.Emoji(output.EmojiSuccess, "Summary contents uploaded!"))
291+
client.out.WriteLine(output.Emoji(output.EmojiSuccess, "File(s) uploaded successfully!"))
281292
return nil
282293
}
283294

@@ -291,7 +302,7 @@ func streamFileToBucket(ctx context.Context, file *uploadFile, bucket *storage.B
291302
// To assert against actual file size
292303
var totalBytesWritten int64
293304

294-
// Do a partial copy, that filters out incompatible statements
305+
// Start a partial copy, that filters out incompatible statements
295306
if file.filterSQL {
296307
bytesWritten, err := pgdump.FilterInvalidLines(writer, file.file, progressFn)
297308
if err != nil {

0 commit comments

Comments
 (0)