From f335e01f0f49be04dd5e2405e7d0c2d7407be148 Mon Sep 17 00:00:00 2001 From: Eric Fritz Date: Thu, 20 May 2021 13:49:36 -0500 Subject: [PATCH 1/3] Squash commits. --- cmd/src/lsif_upload.go | 470 ++++++++++++----------------------- cmd/src/lsif_upload_flags.go | 191 ++++++++++++++ go.mod | 9 +- go.sum | 99 +++++++- internal/api/api.go | 3 +- internal/api/gzip.go | 31 +++ internal/api/gzip_test.go | 34 +++ internal/codeintel/upload.go | 25 -- 8 files changed, 504 insertions(+), 358 deletions(-) create mode 100644 cmd/src/lsif_upload_flags.go create mode 100644 internal/api/gzip.go create mode 100644 internal/api/gzip_test.go delete mode 100644 internal/codeintel/upload.go diff --git a/cmd/src/lsif_upload.go b/cmd/src/lsif_upload.go index 7880ac413f..59067b20d3 100644 --- a/cmd/src/lsif_upload.go +++ b/cmd/src/lsif_upload.go @@ -1,22 +1,19 @@ package main import ( + "encoding/base64" "encoding/json" "flag" "fmt" - "net/http" "net/url" "os" - "sort" "strings" - "sync" "time" - "github.com/efritz/pentimento" "github.com/pkg/browser" - "github.com/pkg/errors" - "github.com/sourcegraph/sourcegraph/lib/codeintel/utils" - "github.com/sourcegraph/src-cli/internal/codeintel" + + "github.com/sourcegraph/sourcegraph/lib/codeintel/upload" + "github.com/sourcegraph/sourcegraph/lib/output" ) func init() { @@ -40,289 +37,163 @@ Examples: $ src lsif upload -indexer=lsif-elixir ` - var flags struct { - repo *string - commit *string - file *string - root *string - indexer *string - gitHubToken *string - open *bool - json *bool - noProgress *bool - maxPayloadSizeMb *int - ignoreUploadFailures *bool - uploadRoute *string - rawVerbosity *int - verbosity lsifUploadVerbosity - associatedIndexID *int - } - - flagSet := flag.NewFlagSet("upload", flag.ExitOnError) - flags.repo = flagSet.String("repo", "", `The name of the repository (e.g. github.com/gorilla/mux). By default, derived from the origin remote.`) - flags.commit = flagSet.String("commit", "", `The 40-character hash of the commit. Defaults to the currently checked-out commit.`) - flags.root = flagSet.String("root", "", `The path in the repository that matches the LSIF projectRoot (e.g. cmd/project1). Defaults to the directory where the dump file is located.`) - flags.file = flagSet.String("file", "./dump.lsif", `The path to the LSIF dump file.`) - flags.indexer = flagSet.String("indexer", "", `The name of the indexer that generated the dump. This will override the 'toolInfo.name' field in the metadata vertex of the LSIF dump file. This must be supplied if the indexer does not set this field (in which case the upload will fail with an explicit message).`) - flags.gitHubToken = flagSet.String("github-token", "", `A GitHub access token with 'public_repo' scope that Sourcegraph uses to verify you have access to the repository.`) - flags.open = flagSet.Bool("open", false, `Open the LSIF upload page in your browser.`) - flags.json = flagSet.Bool("json", false, `Output relevant state in JSON on success.`) - flags.noProgress = flagSet.Bool("no-progress", false, `Do not display a progress bar.`) - flags.maxPayloadSizeMb = flagSet.Int("max-payload-size", 100, `The maximum upload size (in megabytes). Indexes exceeding this limit will be uploaded over multiple HTTP requests.`) - flags.ignoreUploadFailures = flagSet.Bool("ignore-upload-failure", false, `Exit with status code zero on upload failure.`) - flags.uploadRoute = flagSet.String("upload-route", "/.api/lsif/upload", "The path of the upload route. For internal use only.") - flags.rawVerbosity = flagSet.Int("trace", 0, "-trace=0 shows no logs; -trace=1 shows requests and response metadata; -trace=2 shows headers, -trace=3 shows response body") - flags.associatedIndexID = flagSet.Int("associated-index-id", -1, "ID of the associated index record for this upload. For internal use only.") - - parseAndValidateFlags := func(args []string) error { - if err := flagSet.Parse(args); err != nil { - return err - } - - type inferError struct { - argument string - err error - } - var inferErrors []inferError - - if _, err := os.Stat(*flags.file); os.IsNotExist(err) { - inferErrors = append(inferErrors, inferError{"file", err}) - } - - if *flags.repo == "" { - if repo, err := codeintel.InferRepo(); err != nil { - inferErrors = append(inferErrors, inferError{"repo", err}) - } else { - flags.repo = &repo - } - } - - if *flags.commit == "" { - if commit, err := codeintel.InferCommit(); err != nil { - inferErrors = append(inferErrors, inferError{"commit", err}) - } else { - flags.commit = &commit - } - } - - if !isFlagSet(flagSet, "root") { - if root, err := codeintel.InferRoot(*flags.file); err != nil { - inferErrors = append(inferErrors, inferError{"root", err}) - } else { - flags.root = &root - } - } - *flags.root = codeintel.SanitizeRoot(*flags.root) - - if *flags.indexer == "" { - file, err := os.Open(*flags.file) - if err != nil { - inferErrors = append(inferErrors, inferError{"indexer", err}) - } - defer file.Close() - - if indexer, err := codeintelutils.ReadIndexerName(file); err != nil { - inferErrors = append(inferErrors, inferError{"indexer", err}) - } else { - flags.indexer = &indexer - } - } - - argsString := strings.Join([]string{ - "Inferred arguments:", - fmt.Sprintf(" -repo=%s", *flags.repo), - fmt.Sprintf(" -commit=%s", *flags.commit), - fmt.Sprintf(" -root=%s", *flags.root), - fmt.Sprintf(" -file=%s", *flags.file), - fmt.Sprintf(" -indexer=%s", *flags.indexer), - "", - }, "\n") - - for _, v := range inferErrors { - return errors.New(strings.Join([]string{ - fmt.Sprintf("error: %s", v.err), - fmt.Sprintf("Unable to determine %s from environment. Either cd into a git repository or set -%s explicitly.", v.argument, v.argument), - argsString, - }, "\n\n")) - } - - if strings.HasPrefix(*flags.root, "..") { - return errors.New("root must not be outside of repository") - } - - if *flags.maxPayloadSizeMb <= 0 { - return errors.New("max-payload-size must be positive") - } - - // Don't need to check upper bounds as we only compare verbosity ranges - // It's fine if someone supplies -trace=42, but it will just behave the - // same as if they supplied the highest verbosity level we define - // internally. - flags.verbosity = lsifUploadVerbosity(*flags.rawVerbosity) + lsifCommands = append(lsifCommands, &command{ + flagSet: lsifUploadFlagSet, + handler: handleLSIFUpload, + usageFunc: func() { + fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src lsif %s':\n", lsifUploadFlagSet.Name()) + lsifUploadFlagSet.PrintDefaults() + fmt.Println(usage) + }, + }) +} - if !*flags.json { - fmt.Println(argsString) +// handleLSIFUpload is the handler for `src lsif upload`. +func handleLSIFUpload(args []string) error { + err := parseAndValidateLSIFUploadFlags(args) + out := lsifUploadOutput() + if !lsifUploadFlags.json { + if out != nil { + printInferredArguments(out) + } else { + // Always display inferred arguments except when -json is set + printInferredArguments(emergencyOutput()) } + } + if err != nil { + // note: exits the process + handleLSIFUploadError(nil, err) + } - if *flags.associatedIndexID < 0 { - flags.associatedIndexID = nil - } + uploadID, err := upload.UploadIndex(lsifUploadFlags.file, lsifUploadOptions(out)) + if err != nil { + // note: exits the process + handleLSIFUploadError(out, err) + } - return nil + uploadURL, err := makeLSIFUploadURL(uploadID) + if err != nil { + return err } - handler := func(args []string) error { - if err := parseAndValidateFlags(args); err != nil { - return &usageError{err} + if lsifUploadFlags.json { + serialized, err := json.Marshal(map[string]interface{}{ + "repo": lsifUploadFlags.repo, + "commit": lsifUploadFlags.commit, + "root": lsifUploadFlags.root, + "file": lsifUploadFlags.file, + "indexer": lsifUploadFlags.indexer, + "uploadId": uploadID, + "uploadUrl": uploadURL, + }) + if err != nil { + return err } - opts := codeintel.UploadIndexOpts{ - Endpoint: cfg.Endpoint, - AccessToken: cfg.AccessToken, - AdditionalHeaders: cfg.AdditionalHeaders, - Path: *flags.uploadRoute, - Repo: *flags.repo, - Commit: *flags.commit, - Root: *flags.root, - Indexer: *flags.indexer, - GitHubToken: *flags.gitHubToken, - File: *flags.file, - MaxPayloadSizeBytes: *flags.maxPayloadSizeMb * 1000 * 1000, - AssociatedIndexID: flags.associatedIndexID, - MaxRetries: 10, - RetryInterval: time.Millisecond * 250, - UploadProgressEvents: make(chan codeintelutils.UploadProgressEvent), - Logger: &lsifUploadRequestLogger{verbosity: flags.verbosity}, + fmt.Println(string(serialized)) + } else { + if out == nil { + out = emergencyOutput() } - var wg sync.WaitGroup - wg.Add(1) - - go func() { - defer wg.Done() - - if *flags.json || *flags.noProgress || flags.verbosity > 0 { - return - } - - _ = pentimento.PrintProgress(func(p *pentimento.Printer) error { - for event := range opts.UploadProgressEvents { - content := pentimento.NewContent() - content.AddLine(formatProgressBar(event.TotalProgress, fmt.Sprintf("%d/%d", event.Part, event.NumParts))) - _ = p.WriteContent(content) - } - - _ = p.Reset() - return nil - }) - }() - - uploadID, err := codeintel.UploadIndex(opts) - close(opts.UploadProgressEvents) // Stop progress bar updates - wg.Wait() // Wait for progress bar goroutine to clear screen - if err != nil { - if err == codeintelutils.ErrUnauthorized { - err = errorWithHint{ - err: err, hint: strings.Join([]string{ - "You may need to specify or update your GitHub access token to use this endpoint.", - "See https://docs.sourcegraph.com/cli/references/lsif/upload.", - }, "\n"), - } - - } - - if *flags.ignoreUploadFailures { - // Report but don't return - fmt.Println(err.Error()) - err = nil - } - - return err - } + out.WriteLine(output.Linef(output.EmojiLightbulb, output.StyleItalic, "View processing status at %s", uploadURL)) + } - endpointWithoutAuth, err := url.Parse(cfg.Endpoint) - if err != nil { + if lsifUploadFlags.open { + if err := browser.OpenURL(uploadURL); err != nil { return err } - endpointWithoutAuth.User = nil - - uploadURL := fmt.Sprintf("%s/%s/-/settings/code-intelligence/lsif-uploads/%s", endpointWithoutAuth.String(), *flags.repo, uploadID) - - if *flags.json { - serialized, err := json.Marshal(map[string]interface{}{ - "repo": *flags.repo, - "commit": *flags.commit, - "root": *flags.root, - "file": *flags.file, - "indexer": *flags.indexer, - "uploadId": uploadID, - "uploadUrl": uploadURL, - }) - if err != nil { - return err - } - - fmt.Println(string(serialized)) - } else { - fmt.Printf("LSIF dump successfully uploaded for processing.\n") - fmt.Printf("View processing status at %s\n", uploadURL) - } + } - if *flags.open { - if err := browser.OpenURL(uploadURL); err != nil { - return err - } - } + return nil +} +// lsifUploadOutput returns an output object that should be used to print the progres +// of requests made during this upload. If -json, -no-progress, or -trace>0 is given, +// then no output object is defined. +// +// For -no-progress and -trace>0 conditions, emergency loggers will be used to display +// inferred arguments and the URL at which processing status is shown. +func lsifUploadOutput() (out *output.Output) { + if lsifUploadFlags.json || lsifUploadFlags.noProgress || lsifUploadFlags.verbosity > 0 { return nil } - lsifCommands = append(lsifCommands, &command{ - flagSet: flagSet, - handler: handler, - usageFunc: func() { - fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src lsif %s':\n", flagSet.Name()) - flagSet.PrintDefaults() - fmt.Println(usage) - }, + return output.NewOutput(flag.CommandLine.Output(), output.OutputOpts{ + Verbose: true, }) } -func isFlagSet(fs *flag.FlagSet, name string) (found bool) { - fs.Visit(func(f *flag.Flag) { - if f.Name == name { - found = true - } - }) +// lsifUploadOptions creates a set of upload options given the values in the flags. +func lsifUploadOptions(out *output.Output) upload.UploadOptions { + var associatedIndexID *int + if lsifUploadFlags.associatedIndexID != -1 { + associatedIndexID = &lsifUploadFlags.associatedIndexID + } - return found -} + logger := upload.NewRequestLogger( + os.Stdout, + // Don't need to check upper bounds as we only compare verbosity ranges + // It's fine if someone supplies -trace=42, but it will just behave the + // same as if they supplied the highest verbosity level we define + // internally. + upload.RequestLoggerVerbosity(lsifUploadFlags.verbosity), + ) -// maxDisplayWidth is the number of columns that can be used to draw a progress bar. -const maxDisplayWidth = 80 + return upload.UploadOptions{ + UploadRecordOptions: upload.UploadRecordOptions{ + Repo: lsifUploadFlags.repo, + Commit: lsifUploadFlags.commit, + Root: lsifUploadFlags.root, + Indexer: lsifUploadFlags.indexer, + AssociatedIndexID: associatedIndexID, + }, + SourcegraphInstanceOptions: upload.SourcegraphInstanceOptions{ + SourcegraphURL: cfg.Endpoint, + AccessToken: cfg.AccessToken, + AdditionalHeaders: cfg.AdditionalHeaders, + MaxRetries: 5, + RetryInterval: time.Second, + Path: lsifUploadFlags.uploadRoute, + GitHubToken: lsifUploadFlags.gitHubToken, + MaxPayloadSizeBytes: lsifUploadFlags.maxPayloadSizeMb * 1000 * 1000, + }, + OutputOptions: upload.OutputOptions{ + Output: out, + Logger: logger, + }, + } +} -// formatProgressBar draws a progress bar with the given percentage complete and the -// given literal suffix. -func formatProgressBar(progress float64, suffix string) string { - if len(suffix) > 0 { - suffix = " " + suffix +//printInferredArguments prints a block showing the effective values of flags that are +// inferrably defined. This function is called on all paths except for -json uploads. This +// function no-ops if the given output object is nil. +func printInferredArguments(out *output.Output) { + if out == nil { + return } - maxWidth := maxDisplayWidth - 3 - len(suffix) - width := int(float64(maxWidth) * float64(progress)) + block := out.Block(output.Line(output.EmojiLightbulb, output.StyleItalic, "Inferred arguments")) + block.Writef("repo: %s", lsifUploadFlags.repo) + block.Writef("commit: %s", lsifUploadFlags.commit) + block.Writef("root: %s", lsifUploadFlags.root) + block.Writef("file: %s", lsifUploadFlags.file) + block.Writef("indexer: %s", lsifUploadFlags.indexer) + block.Close() +} - var arrow string - if width < maxWidth { - arrow = ">" +// makeLSIFUploadURL constructs a URL to the upload with the given internal identifier. +// The base of the URL is constructed from the configured Sourcegraph instance. +func makeLSIFUploadURL(uploadID int) (string, error) { + url, err := url.Parse(cfg.Endpoint) + if err != nil { + return "", err } - return fmt.Sprintf( - "[%s%s%s]%s", - strings.Repeat("=", width), - arrow, - strings.Repeat(" ", maxWidth-width-len(arrow)), - suffix, - ) + graphqlID := string(base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf(`LSIFUpload:"%d"`, uploadID)))) + url.Path = lsifUploadFlags.repo + "/-/settings/code-intelligence/lsif-uploads/" + graphqlID + url.User = nil + return url.String(), nil } type errorWithHint struct { @@ -331,69 +202,36 @@ type errorWithHint struct { } func (e errorWithHint) Error() string { - return fmt.Sprintf("error: %s\n\n%s\n", e.err, e.hint) -} - -type lsifUploadVerbosity int - -const ( - lsifUploadVerbosityNone lsifUploadVerbosity = iota // -trace=0 (default) - lsifUploadVerbosityTrace // -trace=1 - lsifUploadVerbosityTraceShowHeaders // -trace=2 - lsifUploadVerbosityTraceShowResponseBody // -trace=3 -) - -type lsifUploadRequestLogger struct { - verbosity lsifUploadVerbosity -} - -func (l *lsifUploadRequestLogger) LogRequest(req *http.Request) { - if l.verbosity == lsifUploadVerbosityNone { - return - } - - if l.verbosity >= lsifUploadVerbosityTrace { - fmt.Printf("> %s %s\n", req.Method, req.URL) - } - - if l.verbosity >= lsifUploadVerbosityTraceShowHeaders { - fmt.Printf("> Request Headers:\n") - for _, k := range sortHeaders(req.Header) { - fmt.Printf("> %s: %s\n", k, req.Header[k]) - } - } - - fmt.Printf("\n") + return fmt.Sprintf("%s\n\n%s\n", e.err, e.hint) } -func (l *lsifUploadRequestLogger) LogResponse(req *http.Request, resp *http.Response, body []byte, elapsed time.Duration) { - if l.verbosity == lsifUploadVerbosityNone { - return - } - - if l.verbosity >= lsifUploadVerbosityTrace { - fmt.Printf("< %s %s %s in %s\n", req.Method, req.URL, resp.Status, elapsed) +var errUnauthorizedHint = strings.Join([]string{ + "You may need to specify or update your GitHub access token to use this endpoint.", + "See https://docs.sourcegraph.com/cli/references/lsif/upload.", +}, "\n") + +// handleLSIFUploadError writes the given error to the given output and then +// exits the process. If the given output object is nil then the error will +// be written to standard out. +func handleLSIFUploadError(out *output.Output, err error) { + if out == nil { + out = emergencyOutput() } - if l.verbosity >= lsifUploadVerbosityTraceShowHeaders { - fmt.Printf("< Response Headers:\n") - for _, k := range sortHeaders(resp.Header) { - fmt.Printf("< %s: %s\n", k, resp.Header[k]) - } + if err == upload.ErrUnauthorized { + err = errorWithHint{err: err, hint: errUnauthorizedHint} } + out.WriteLine(output.Linef(output.EmojiFailure, output.StyleWarning, "error: %s", err)) - if l.verbosity >= lsifUploadVerbosityTraceShowResponseBody { - fmt.Printf("< Response Body: %s\n", body) + if !lsifUploadFlags.ignoreUploadFailures { + // Report but don't return the error + os.Exit(0) } - fmt.Printf("\n") + os.Exit(1) } -func sortHeaders(header http.Header) []string { - var keys []string - for k := range header { - keys = append(keys, k) - } - sort.Strings(keys) - return keys +// emergencyOutput creates a default Output object writing to standard out. +func emergencyOutput() *output.Output { + return output.NewOutput(os.Stdout, output.OutputOpts{}) } diff --git a/cmd/src/lsif_upload_flags.go b/cmd/src/lsif_upload_flags.go new file mode 100644 index 0000000000..29a6d68afe --- /dev/null +++ b/cmd/src/lsif_upload_flags.go @@ -0,0 +1,191 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "os" + "strings" + + "github.com/sourcegraph/sourcegraph/lib/codeintel/upload" + "github.com/sourcegraph/src-cli/internal/codeintel" +) + +var lsifUploadFlags struct { + file string + + // UploadRecordOptions + repo string + commit string + root string + indexer string + associatedIndexID int + + // SourcegraphInstanceOptions + uploadRoute string + gitHubToken string + maxPayloadSizeMb int64 + + // Output and error behavior + ignoreUploadFailures bool + noProgress bool + verbosity int + json bool + open bool +} + +var lsifUploadFlagSet = flag.NewFlagSet("upload", flag.ExitOnError) + +func init() { + lsifUploadFlagSet.StringVar(&lsifUploadFlags.file, "file", "./dump.lsif", `The path to the LSIF dump file.`) + + // UploadRecordOptions + lsifUploadFlagSet.StringVar(&lsifUploadFlags.repo, "repo", "", `The name of the repository (e.g. github.com/gorilla/mux). By default, derived from the origin remote.`) + lsifUploadFlagSet.StringVar(&lsifUploadFlags.commit, "commit", "", `The 40-character hash of the commit. Defaults to the currently checked-out commit.`) + lsifUploadFlagSet.StringVar(&lsifUploadFlags.root, "root", "", `The path in the repository that matches the LSIF projectRoot (e.g. cmd/project1). Defaults to the directory where the dump file is located.`) + lsifUploadFlagSet.StringVar(&lsifUploadFlags.indexer, "indexer", "", `The name of the indexer that generated the dump. This will override the 'toolInfo.name' field in the metadata vertex of the LSIF dump file. This must be supplied if the indexer does not set this field (in which case the upload will fail with an explicit message).`) + lsifUploadFlagSet.IntVar(&lsifUploadFlags.associatedIndexID, "associated-index-id", -1, "ID of the associated index record for this upload. For internal use only.") + + // SourcegraphInstanceOptions + lsifUploadFlagSet.StringVar(&lsifUploadFlags.uploadRoute, "upload-route", "/.api/lsif/upload", "The path of the upload route. For internal use only.") + lsifUploadFlagSet.StringVar(&lsifUploadFlags.gitHubToken, "github-token", "", `A GitHub access token with 'public_repo' scope that Sourcegraph uses to verify you have access to the repository.`) + lsifUploadFlagSet.Int64Var(&lsifUploadFlags.maxPayloadSizeMb, "max-payload-size", 100, `The maximum upload size (in megabytes). Indexes exceeding this limit will be uploaded over multiple HTTP requests.`) + + // Output and error behavior + lsifUploadFlagSet.BoolVar(&lsifUploadFlags.ignoreUploadFailures, "ignore-upload-failure", false, `Exit with status code zero on upload failure.`) + lsifUploadFlagSet.BoolVar(&lsifUploadFlags.noProgress, "no-progress", false, `Do not display progress updates.`) + lsifUploadFlagSet.IntVar(&lsifUploadFlags.verbosity, "trace", 0, "-trace=0 shows no logs; -trace=1 shows requests and response metadata; -trace=2 shows headers, -trace=3 shows response body") + lsifUploadFlagSet.BoolVar(&lsifUploadFlags.json, "json", false, `Output relevant state in JSON on success.`) + lsifUploadFlagSet.BoolVar(&lsifUploadFlags.open, "open", false, `Open the LSIF upload page in your browser.`) +} + +// parseAndValidateLSIFUploadFlags calls lsifUploadFlagSet.Parse, then infers values for +// missing flags, normalizes supplied values, and validates the state of the lsifUploadFlags +// object. +// +// On success, the global lsifUploadFlags object will be populated with valid values. An +// error is returned on failure. +func parseAndValidateLSIFUploadFlags(args []string) error { + if err := lsifUploadFlagSet.Parse(args); err != nil { + return err + } + + if inferenceErrors := inferMissingLSIFUploadFlags(); len(inferenceErrors) > 0 { + return errorWithHint{ + err: inferenceErrors[0].err, hint: strings.Join([]string{ + fmt.Sprintf( + "Unable to determine %s from environment. Check your working directory or supply -%s={value} explicitly", + inferenceErrors[0].argument, + inferenceErrors[0].argument, + ), + }, "\n"), + } + } + + if err := validateLSIFUploadFlags(); err != nil { + return err + } + + return nil +} + +type argumentInferenceError struct { + argument string + err error +} + +// inferMissingLSIFUploadFlags updates the flags values which were not explicitly +// supplied by the user with default values inferred from the current git state and +// filesystem. +// +// Note: This function must not be called before lsifUploadFlagSet.Parse. +func inferMissingLSIFUploadFlags() (inferErrors []argumentInferenceError) { + if _, err := os.Stat(lsifUploadFlags.file); os.IsNotExist(err) { + inferErrors = append(inferErrors, argumentInferenceError{"file", err}) + } + + if err := inferUnsetFlag("repo", &lsifUploadFlags.repo, codeintel.InferRepo); err != nil { + inferErrors = append(inferErrors, *err) + } + if err := inferUnsetFlag("commit", &lsifUploadFlags.commit, codeintel.InferCommit); err != nil { + inferErrors = append(inferErrors, *err) + } + if err := inferUnsetFlag("root", &lsifUploadFlags.root, inferIndexRoot); err != nil { + inferErrors = append(inferErrors, *err) + } + if err := inferUnsetFlag("indexer", &lsifUploadFlags.indexer, readIndexerName); err != nil { + inferErrors = append(inferErrors, *err) + } + + return inferErrors +} + +// inferUnsetFlag conditionally updates the value of the given pointer with the +// return value of the given function. If the flag with the given name was supplied +// by the user, then this function no-ops. An argumentInferenceError is returned if +// the given function returns an error. +// +// Note: This function must not be called before lsifUploadFlagSet.Parse. +func inferUnsetFlag(name string, target *string, f func() (string, error)) *argumentInferenceError { + if isFlagSet(lsifUploadFlagSet, name) { + return nil + } + + value, err := f() + if err != nil { + return &argumentInferenceError{name, err} + } + + *target = value + return nil +} + +// isFlagSet returns true if the flag with the given name was supplied by the user. +// This lets us distinguish between zero-values (empty strings) and void values without +// requiring pointers and adding a layer of indirection deeper in the program. +func isFlagSet(fs *flag.FlagSet, name string) (found bool) { + fs.Visit(func(f *flag.Flag) { + if f.Name == name { + found = true + } + }) + + return found +} + +// inferIndexRoot returns the root directory based on the configured index file path. +// +// Note: This function must not be called before lsifUploadFlagSet.Parse. +func inferIndexRoot() (string, error) { + return codeintel.InferRoot(lsifUploadFlags.file) +} + +// readIndexerName returns the indexer name read from the configured index file. +// +// Note: This function must not be called before lsifUploadFlagSet.Parse. +func readIndexerName() (string, error) { + file, err := os.Open(lsifUploadFlags.file) + if err != nil { + return "", err + } + defer file.Close() + + return upload.ReadIndexerName(file) +} + +// validateLSIFUploadFlags returns an error if any of the parsed flag values are illegal. +// +// Note: This function must not be called before lsifUploadFlagSet.Parse. +func validateLSIFUploadFlags() error { + lsifUploadFlags.root = codeintel.SanitizeRoot(lsifUploadFlags.root) + + if strings.HasPrefix(lsifUploadFlags.root, "..") { + return errors.New("root must not be outside of repository") + } + + if lsifUploadFlags.maxPayloadSizeMb < 25 { + return errors.New("max-payload-size must be at least 25 (MB)") + } + + return nil +} diff --git a/go.mod b/go.mod index fbfd1e0dcd..dc9a310eef 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,11 @@ go 1.13 require ( github.com/Masterminds/semver v1.5.0 github.com/dustin/go-humanize v1.0.0 - github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101 github.com/gobwas/glob v0.2.3 github.com/google/go-cmp v0.5.5 github.com/hashicorp/go-multierror v1.1.1 github.com/jig/teereadcloser v0.0.0-20181016160506-953720c48e05 - github.com/json-iterator/go v1.1.10 + github.com/json-iterator/go v1.1.11 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/mattn/go-isatty v0.0.12 github.com/neelance/parallel v0.0.0-20160708114440-4de9ce63d14c @@ -25,8 +24,8 @@ require ( github.com/sourcegraph/sourcegraph/lib v0.0.0-20210425142047-b8f4790093e5 github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - golang.org/x/net v0.0.0-20200625001655-4c5254603344 - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e + golang.org/x/net v0.0.0-20201021035429-f5854403a974 + golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 // indirect gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 jaytaylor.com/html2text v0.0.0-20200412013138-3577fbdbcff7 @@ -36,3 +35,5 @@ replace github.com/gosuri/uilive v0.0.4 => github.com/mrnugget/uilive v0.0.4-fix // See: https://github.com/ghodss/yaml/pull/65 replace github.com/ghodss/yaml => github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152 + +replace github.com/sourcegraph/sourcegraph/lib => ../sourcegraph/lib diff --git a/go.sum b/go.sum index 10925ed7fb..cd2a3c261c 100644 --- a/go.sum +++ b/go.sum @@ -1,46 +1,89 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/aphistic/sweet v0.0.0-20180618201346-68e18ab55a67/go.mod h1:iggGz3Cujwru5rGKuOi4u1rfI+38suzhVVJj8Ey7Q3M= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +github.com/aphistic/sweet-junit v0.0.0-20190314030539-8d7e248096c2/go.mod h1:+eL69RqmiKF2Jm3poefxF/ZyVNGXFdSsPq3ScBFtX9s= +github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101 h1:RylpU+KNJJNEJIk3o8gZ70uPTlutxaYnikKNPko39LA= +github.com/efritz/go-genlib v0.0.0-20200420163202-9c3914df9594/go.mod h1:aMnaM7yzn10TOdj5sGpElY90l/XT3eL+Sj7z7D1V8q8= +github.com/efritz/go-mockgen v0.0.0-20200916004441-cfcabc111002/go.mod h1:K2AZyo7TmaAzRhr4EvUaEHcpumiT0UEAARFnSBid7yE= github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101/go.mod h1:5ALWO82UZwfAtNRUtwzsWimcrcuYzyieTyyXOXrP6EQ= +github.com/fatih/color v1.11.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hexops/autogold v0.8.1/go.mod h1:97HLDXyG23akzAoRYJh/2OBs3kd80eHyKPvZw0S5ZBY= +github.com/hexops/autogold v1.3.0/go.mod h1:d4hwi2rid66Sag+BVuHgwakW/EmaFr8vdTSbWDbrDRI= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/hexops/valast v1.4.0/go.mod h1:uVjKZ0smVuYlgCSPz9NRi5A04sl7lp6GtFWsROKDgEs= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/jig/teereadcloser v0.0.0-20181016160506-953720c48e05 h1:dSwwtWuwMyarzsbVWOq4QJ8xVy9wgcNomvWyGtrKe+E= github.com/jig/teereadcloser v0.0.0-20181016160506-953720c48e05/go.mod h1:sRUFlj+HCejvoCRpuhU0EYnNw5FG+YJpz8UFfCf0F2U= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/neelance/parallel v0.0.0-20160708114440-4de9ce63d14c h1:NZOii9TDGRAfCS5VM16XnF4K7afoLQmIiZX8EkKnxtE= github.com/neelance/parallel v0.0.0-20160708114440-4de9ce63d14c/go.mod h1:eTBvSIlRgLo+CNFFQRQTwUGTZOEdvXIKeZS/xG+D2yU= +github.com/nightlyone/lockfile v1.0.0/go.mod h1:rywoIealpdNse2r832aiD9jRk8ErCatROs6LzC841CI= github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/nsf/termbox-go v1.0.0 h1:i1ohxKvN1/5WJ5VHOdmy/Ps0iiblAzgtqhhozNT1nhA= github.com/nsf/termbox-go v1.0.0/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -50,23 +93,25 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/go-goon v0.0.0-20210110234559-7585751d9a17/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sourcegraph/batch-change-utils v0.0.0-20210309183117-206c057cc03e h1:8dpmTar1H4dS4f3WWTtG6FSK/GbjQl7alHRJlzNY0lo= github.com/sourcegraph/batch-change-utils v0.0.0-20210309183117-206c057cc03e/go.mod h1:kKNRPN6dxuXwC4UUhPVcAJsvz4EVEfI0jyN5HUJsazA= github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0HZqLQ= github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf h1:oAdWFqhStsWiiMP/vkkHiMXqFXzl1XfUNOdxKJbd6bI= github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf/go.mod h1:ppFaPm6kpcHnZGqQTFhUIAQRIEhdQDWP1PCv4/ON354= -github.com/sourcegraph/sourcegraph/lib v0.0.0-20210425142047-b8f4790093e5 h1:jE/jTSVbwxtCDBmoCMhzjEBEiHBrjv0+AHbdhtb+nPs= -github.com/sourcegraph/sourcegraph/lib v0.0.0-20210425142047-b8f4790093e5/go.mod h1:NopPnbkgFn6YDGOhy0+VQ/WH41U80IVfJSHxtebQyuo= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152 h1:z/MpntplPaW6QW95pzcAR/72Z5TWDyDnSo0EOcyij9o= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -75,42 +120,72 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190428183149-804c0c7841b5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210218084038-e8e29180ff58/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190428024724-550556f78a90/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191224055732-dd894d0a8a40/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200420001825-978e26b7c37c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200624163319-25775e59acb7/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -118,3 +193,5 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclp gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= jaytaylor.com/html2text v0.0.0-20200412013138-3577fbdbcff7 h1:mub0MmFLOn8XLikZOAhgLD1kXJq8jgftSrrv7m00xFo= jaytaylor.com/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:OxvTsCwKosqQ1q7B+8FwXqg4rKZ/UG9dUW+g/VL2xH4= +mvdan.cc/gofumpt v0.0.0-20210107193838-d24d34e18d44/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= +mvdan.cc/gofumpt v0.1.0/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= diff --git a/internal/api/api.go b/internal/api/api.go index 3327869ee3..221edbb9ec 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -16,7 +16,6 @@ import ( ioaux "github.com/jig/teereadcloser" "github.com/kballard/go-shellquote" "github.com/mattn/go-isatty" - "github.com/sourcegraph/sourcegraph/lib/codeintel/utils" ) // Client instances provide methods to create API requests. @@ -212,7 +211,7 @@ func (r *request) do(ctx context.Context, result interface{}) (bool, error) { var bufBody io.Reader = bytes.NewBuffer(reqBody) if r.gzip { - bufBody = codeintelutils.Gzip(bufBody) + bufBody = gzipReader(bufBody) } // Create the HTTP request. diff --git a/internal/api/gzip.go b/internal/api/gzip.go new file mode 100644 index 0000000000..a9445c1483 --- /dev/null +++ b/internal/api/gzip.go @@ -0,0 +1,31 @@ +package api + +import ( + "compress/gzip" + "io" + + "github.com/hashicorp/go-multierror" +) + +// gzipReader decorates a source reader by gzip compressing its contents. +func gzipReader(source io.Reader) io.Reader { + r, w := io.Pipe() + go func() { + // propagate gzip write errors into new reader + w.CloseWithError(gzipPipe(source, w)) + }() + return r +} + +// gzipPipe reads uncompressed data from r and writes compressed data to w. +func gzipPipe(r io.Reader, w io.Writer) (err error) { + gzipWriter := gzip.NewWriter(w) + defer func() { + if closeErr := gzipWriter.Close(); closeErr != nil { + err = multierror.Append(err, err) + } + }() + + _, err = io.Copy(gzipWriter, r) + return err +} diff --git a/internal/api/gzip_test.go b/internal/api/gzip_test.go new file mode 100644 index 0000000000..5cca5ee585 --- /dev/null +++ b/internal/api/gzip_test.go @@ -0,0 +1,34 @@ +package api + +import ( + "bytes" + "compress/gzip" + "io/ioutil" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestGzipReader(t *testing.T) { + var uncompressed []byte + for i := 0; i < 20000; i++ { + uncompressed = append(uncompressed, byte(i)) + } + + contents, err := ioutil.ReadAll(gzipReader(bytes.NewReader(uncompressed))) + if err != nil { + t.Fatalf("unexpected error reading from gzip reader: %s", err) + } + + gzipReader, err := gzip.NewReader(bytes.NewReader(contents)) + if err != nil { + t.Fatalf("unexpected error creating gzip.Reader: %s", err) + } + decompressed, err := ioutil.ReadAll(gzipReader) + if err != nil { + t.Fatalf("unexpected error reading from gzip.Reader: %s", err) + } + if diff := cmp.Diff(decompressed, uncompressed); diff != "" { + t.Errorf("unexpected gzipped contents (-want +got):\n%s", diff) + } +} diff --git a/internal/codeintel/upload.go b/internal/codeintel/upload.go deleted file mode 100644 index 99f65aa9de..0000000000 --- a/internal/codeintel/upload.go +++ /dev/null @@ -1,25 +0,0 @@ -package codeintel - -import ( - "encoding/base64" - "fmt" - - "github.com/sourcegraph/sourcegraph/lib/codeintel/utils" -) - -type UploadIndexOpts = codeintelutils.UploadIndexOpts - -func UploadIndex(opts UploadIndexOpts) (string, error) { - id, err := codeintelutils.UploadIndex(opts) - if err != nil { - return "", err - } - - return uploadIDToGraphQLID(id), nil -} - -// uploadIndex constructs a GraphQL-compatible identifier from the raw identifier returned -// from the upload endpoint. -func uploadIDToGraphQLID(uploadID int) string { - return string(base64.URLEncoding.EncodeToString([]byte(fmt.Sprintf(`LSIFUpload:"%d"`, uploadID)))) -} From 8d10caef9f0b5e44891bb1c275fb0277198f68a1 Mon Sep 17 00:00:00 2001 From: Eric Fritz Date: Thu, 20 May 2021 18:27:47 -0500 Subject: [PATCH 2/3] Update go.mod. --- go.mod | 4 +--- go.sum | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index dc9a310eef..05fae6eb74 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/sourcegraph/batch-change-utils v0.0.0-20210309183117-206c057cc03e github.com/sourcegraph/go-diff v0.6.1 github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf - github.com/sourcegraph/sourcegraph/lib v0.0.0-20210425142047-b8f4790093e5 + github.com/sourcegraph/sourcegraph/lib v0.0.0-20210520231824-520a2ae26af0 github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect golang.org/x/net v0.0.0-20201021035429-f5854403a974 @@ -35,5 +35,3 @@ replace github.com/gosuri/uilive v0.0.4 => github.com/mrnugget/uilive v0.0.4-fix // See: https://github.com/ghodss/yaml/pull/65 replace github.com/ghodss/yaml => github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152 - -replace github.com/sourcegraph/sourcegraph/lib => ../sourcegraph/lib diff --git a/go.sum b/go.sum index cd2a3c261c..f58ef3a643 100644 --- a/go.sum +++ b/go.sum @@ -104,6 +104,8 @@ github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0H github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf h1:oAdWFqhStsWiiMP/vkkHiMXqFXzl1XfUNOdxKJbd6bI= github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf/go.mod h1:ppFaPm6kpcHnZGqQTFhUIAQRIEhdQDWP1PCv4/ON354= +github.com/sourcegraph/sourcegraph/lib v0.0.0-20210520231824-520a2ae26af0 h1:+u8RvcXN9ptLZ8saLCmsDUxtjyKXkWFKUKRhzL7QxbI= +github.com/sourcegraph/sourcegraph/lib v0.0.0-20210520231824-520a2ae26af0/go.mod h1:MRp3GJo/2UxtfAVZx8CwQ/ZD78n6RjXuYfz4RWvszqI= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152 h1:z/MpntplPaW6QW95pzcAR/72Z5TWDyDnSo0EOcyij9o= github.com/sourcegraph/yaml v1.0.1-0.20200714132230-56936252f152/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= From 85f5115902540807b4e3364790198c28456455c5 Mon Sep 17 00:00:00 2001 From: Eric Fritz Date: Fri, 21 May 2021 12:58:54 -0500 Subject: [PATCH 3/3] Refactor error flow. --- cmd/src/lsif_upload.go | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/cmd/src/lsif_upload.go b/cmd/src/lsif_upload.go index 59067b20d3..7a02b7cc2f 100644 --- a/cmd/src/lsif_upload.go +++ b/cmd/src/lsif_upload.go @@ -61,14 +61,12 @@ func handleLSIFUpload(args []string) error { } } if err != nil { - // note: exits the process - handleLSIFUploadError(nil, err) + return handleLSIFUploadError(nil, err) } uploadID, err := upload.UploadIndex(lsifUploadFlags.file, lsifUploadOptions(out)) if err != nil { - // note: exits the process - handleLSIFUploadError(out, err) + return handleLSIFUploadError(out, err) } uploadURL, err := makeLSIFUploadURL(uploadID) @@ -210,25 +208,22 @@ var errUnauthorizedHint = strings.Join([]string{ "See https://docs.sourcegraph.com/cli/references/lsif/upload.", }, "\n") -// handleLSIFUploadError writes the given error to the given output and then -// exits the process. If the given output object is nil then the error will -// be written to standard out. -func handleLSIFUploadError(out *output.Output, err error) { - if out == nil { - out = emergencyOutput() - } - +// handleLSIFUploadError writes the given error to the given output. If the +// given output object is nil then the error will be written to standard out. +// +// This method returns the error that should be passed back up to the runner. +func handleLSIFUploadError(out *output.Output, err error) error { if err == upload.ErrUnauthorized { err = errorWithHint{err: err, hint: errUnauthorizedHint} } - out.WriteLine(output.Linef(output.EmojiFailure, output.StyleWarning, "error: %s", err)) - if !lsifUploadFlags.ignoreUploadFailures { + if lsifUploadFlags.ignoreUploadFailures { // Report but don't return the error - os.Exit(0) + fmt.Println(err.Error()) + return nil } - os.Exit(1) + return err } // emergencyOutput creates a default Output object writing to standard out.