Skip to content

Commit 53e36ab

Browse files
Support pre-compressed uploads in code-intel upload (#1146)
1 parent 98d8cd4 commit 53e36ab

6 files changed

+819
-16
lines changed

.github/workflows/scip.yml

+27-5
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,46 @@ jobs:
1111
container: sourcegraph/scip-go
1212
steps:
1313
- uses: actions/checkout@v4
14-
- name: Get src-cli
15-
run: curl -L https://sourcegraph.com/.api/src-cli/src_linux_amd64 -o /usr/local/bin/src;
16-
chmod +x /usr/local/bin/src
14+
- name: Set up Go
15+
uses: actions/setup-go@v5
16+
with:
17+
go-version: 1.23.2
18+
1719
- name: Set directory to safe for git
1820
run: git config --global --add safe.directory $GITHUB_WORKSPACE
21+
22+
- name: Build src-cli
23+
run: go build -o ./src-cli ./cmd/src
24+
1925
- name: Enable pulling Go modules from private sourcegraph/sourcegraph
2026
run: git config --global url."https://${PRIVATE_TOKEN}@github.com/sourcegraph/".insteadOf "https://github.com/sourcegraph/"
27+
2128
- name: Generate SCIP data
2229
run: scip-go
2330

2431
- name: Upload SCIP to Cloud
25-
run: src code-intel upload -github-token='${{ secrets.GITHUB_TOKEN }}' -no-progress
32+
run: ./src-cli code-intel upload -github-token='${{ secrets.GITHUB_TOKEN }}' -no-progress
2633
env:
2734
SRC_ENDPOINT: https://sourcegraph.com/
2835
SRC_ACCESS_TOKEN: ${{ secrets.SRC_ACCESS_TOKEN_DOTCOM }}
2936

3037
- name: Upload SCIP to S2
31-
run: src code-intel upload -github-token='${{ secrets.GITHUB_TOKEN }}' -no-progress
38+
run: ./src-cli code-intel upload -github-token='${{ secrets.GITHUB_TOKEN }}' -no-progress
39+
env:
40+
SRC_ENDPOINT: https://sourcegraph.sourcegraph.com/
41+
SRC_ACCESS_TOKEN: ${{ secrets.SRC_ACCESS_TOKEN_S2 }}
42+
43+
- name: Compress SCIP file
44+
run: gzip index.scip
45+
46+
- name: Upload compressed SCIP to Cloud
47+
run: ./src-cli code-intel upload -github-token='${{ secrets.GITHUB_TOKEN }}' -no-progress
48+
env:
49+
SRC_ENDPOINT: https://sourcegraph.com/
50+
SRC_ACCESS_TOKEN: ${{ secrets.SRC_ACCESS_TOKEN_DOTCOM }}
51+
52+
- name: Upload compressed SCIP to S2
53+
run: ./src-cli code-intel upload -github-token='${{ secrets.GITHUB_TOKEN }}' -no-progress
3254
env:
3355
SRC_ENDPOINT: https://sourcegraph.sourcegraph.com/
3456
SRC_ACCESS_TOKEN: ${{ secrets.SRC_ACCESS_TOKEN_S2 }}

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ All notable changes to `src-cli` are documented in this file.
1111

1212
## Unreleased
1313

14+
- Support uploading GZIP compressed SCIP indexes [1146](https://github.com/sourcegraph/src-cli/pull/1146)
15+
1416
## 6.0.1
1517

1618
- Container signature verification support: Container signatures can now be verified for Sourcegraph releases after 5.11.4013 using `src signature verify -v <release>` [#1143](https://github.com/sourcegraph/src-cli/pull/1143)
@@ -153,7 +155,7 @@ All notable changes to `src-cli` are documented in this file.
153155

154156
### Fixed
155157

156-
- Fixed `src validate install` requiring `SRC_GITHUB_TOKEN` in all cases. [958](https://github.com/sourcegraph/src-cli/pull/958)
158+
- Fixed `src validate install` requiring `SRC_GITHUB_TOKEN` in all cases. [958](https://github.com/sourcegraph/src-cli/pull/958)
157159

158160
## 5.0.1
159161

cmd/src/code_intel_upload.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,12 @@ func handleCodeIntelUpload(args []string) error {
8282
})
8383

8484
uploadOptions := codeintelUploadOptions(out)
85-
uploadID, err := upload.UploadIndex(ctx, codeintelUploadFlags.file, client, uploadOptions)
85+
var uploadID int
86+
if codeintelUploadFlags.gzipCompressed {
87+
uploadID, err = UploadCompressedIndex(ctx, codeintelUploadFlags.file, client, uploadOptions, 0)
88+
} else {
89+
uploadID, err = UploadUncompressedIndex(ctx, codeintelUploadFlags.file, client, uploadOptions)
90+
}
8691
if err != nil {
8792
return handleUploadError(uploadOptions.SourcegraphInstanceOptions.AccessToken, err)
8893
}

cmd/src/code_intel_upload_flags.go

+74-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package main
22

33
import (
4+
"compress/gzip"
45
"flag"
56
"fmt"
7+
"io"
68
"os"
9+
"path"
710
"strings"
811

912
"github.com/sourcegraph/scip/bindings/go/scip"
@@ -15,7 +18,8 @@ import (
1518
)
1619

1720
var codeintelUploadFlags struct {
18-
file string
21+
file string
22+
gzipCompressed bool
1923

2024
// UploadRecordOptions
2125
repo string
@@ -110,7 +114,7 @@ func parseAndValidateCodeIntelUploadFlags(args []string) (*output.Output, error)
110114
}
111115

112116
if !isFlagSet(codeintelUploadFlagSet, "file") {
113-
defaultFile, err := inferDefaultFile()
117+
defaultFile, err := inferDefaultFile(out)
114118
if err != nil {
115119
return nil, err
116120
}
@@ -131,6 +135,10 @@ func parseAndValidateCodeIntelUploadFlags(args []string) (*output.Output, error)
131135
return nil, errors.Newf("file %q does not exist", codeintelUploadFlags.file)
132136
}
133137

138+
if err := inferGzipFlag(); err != nil {
139+
return nil, err
140+
}
141+
134142
// Infer the remaining default arguments (may require reading from new file)
135143
if inferenceErrors := inferMissingCodeIntelUploadFlags(); len(inferenceErrors) > 0 {
136144
return nil, formatInferenceError(inferenceErrors[0])
@@ -143,6 +151,22 @@ func parseAndValidateCodeIntelUploadFlags(args []string) (*output.Output, error)
143151
return out, nil
144152
}
145153

154+
func inferGzipFlag() error {
155+
if codeintelUploadFlags.gzipCompressed || path.Ext(codeintelUploadFlags.file) == ".gz" {
156+
file, err := os.Open(codeintelUploadFlags.file)
157+
if err != nil {
158+
return err
159+
}
160+
defer file.Close()
161+
if err := checkGzipHeader(file); err != nil {
162+
return errors.Wrapf(err, "could not verify that %s is a valid gzip file", codeintelUploadFlags.file)
163+
}
164+
codeintelUploadFlags.gzipCompressed = true
165+
}
166+
167+
return nil
168+
}
169+
146170
// codeintelUploadOutput returns an output object that should be used to print the progres
147171
// of requests made during this upload. If -json, -no-progress, or -trace>0 is given,
148172
// then no output object is defined.
@@ -164,19 +188,40 @@ type argumentInferenceError struct {
164188
err error
165189
}
166190

167-
func inferDefaultFile() (string, error) {
191+
func inferDefaultFile(out *output.Output) (string, error) {
168192
const scipFilename = "index.scip"
169-
_, err := os.Stat(scipFilename)
193+
const scipCompressedFilename = "index.scip.gz"
170194

171-
if err == nil {
195+
hasSCIP, err := doesFileExist(scipFilename)
196+
if err != nil {
197+
return "", err
198+
}
199+
hasCompressedSCIP, err := doesFileExist(scipCompressedFilename)
200+
if err != nil {
201+
return "", err
202+
}
203+
204+
if !hasSCIP && !hasCompressedSCIP {
205+
return "", formatInferenceError(argumentInferenceError{"file", errors.Newf("Unable to locate SCIP index. Checked paths: %q and %q.", scipFilename, scipCompressedFilename)})
206+
} else if hasCompressedSCIP {
207+
if hasSCIP {
208+
out.WriteLine(output.Linef(output.EmojiInfo, output.StyleBold, "Both %s and %s exist, choosing %s", scipFilename, scipCompressedFilename, scipCompressedFilename))
209+
}
210+
return scipCompressedFilename, nil
211+
} else {
172212
return scipFilename, nil
173213
}
214+
}
174215

216+
func doesFileExist(filename string) (bool, error) {
217+
info, err := os.Stat(filename)
175218
if os.IsNotExist(err) {
176-
return "", formatInferenceError(argumentInferenceError{"file", errors.Newf("%s does not exist", scipFilename)})
219+
return false, nil
220+
} else if err != nil {
221+
return false, err
222+
} else {
223+
return !info.IsDir(), nil
177224
}
178-
179-
return "", err
180225
}
181226

182227
func formatInferenceError(inferenceErr argumentInferenceError) error {
@@ -271,6 +316,17 @@ func readIndexerNameAndVersion(indexFile string) (string, string, error) {
271316
}
272317
defer file.Close()
273318

319+
var indexReader io.Reader = file
320+
321+
if codeintelUploadFlags.gzipCompressed {
322+
gzipReader, err := gzip.NewReader(file)
323+
if err != nil {
324+
return "", "", err
325+
}
326+
indexReader = gzipReader
327+
defer gzipReader.Close()
328+
}
329+
274330
var metadata *scip.Metadata
275331

276332
visitor := scip.IndexVisitor{
@@ -280,7 +336,7 @@ func readIndexerNameAndVersion(indexFile string) (string, string, error) {
280336
}
281337

282338
// convert file to io.Reader
283-
if err := visitor.ParseStreaming(file); err != nil {
339+
if err := visitor.ParseStreaming(indexReader); err != nil {
284340
return "", "", err
285341
}
286342

@@ -307,3 +363,12 @@ func validateCodeIntelUploadFlags() error {
307363

308364
return nil
309365
}
366+
367+
func checkGzipHeader(r io.Reader) error {
368+
gz, err := gzip.NewReader(r)
369+
if err != nil {
370+
return err
371+
}
372+
defer gz.Close()
373+
return nil
374+
}

cmd/src/code_intel_upload_transfer.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"os"
6+
7+
"github.com/sourcegraph/sourcegraph/lib/codeintel/upload"
8+
"github.com/sourcegraph/sourcegraph/lib/output"
9+
)
10+
11+
func UploadUncompressedIndex(ctx context.Context, filename string, httpClient upload.Client, opts upload.UploadOptions) (int, error) {
12+
originalReader, originalSize, err := openFileAndGetSize(filename)
13+
if err != nil {
14+
return 0, err
15+
}
16+
defer func() {
17+
_ = originalReader.Close()
18+
}()
19+
20+
bars := []output.ProgressBar{{Label: "Compressing", Max: 1.0}}
21+
progress, _, cleanup := logProgress(
22+
opts.Output,
23+
bars,
24+
"Index compressed",
25+
"Failed to compress index",
26+
)
27+
28+
compressedFile, err := compressReaderToDisk(originalReader, originalSize, progress)
29+
if err != nil {
30+
cleanup(err)
31+
return 0, err
32+
}
33+
defer func() {
34+
_ = os.Remove(compressedFile)
35+
}()
36+
37+
compressedSize, err := getFileSize(compressedFile)
38+
if err != nil {
39+
cleanup(err)
40+
return 0, err
41+
}
42+
43+
cleanup(nil)
44+
45+
if opts.Output != nil {
46+
opts.Output.WriteLine(output.Linef(
47+
output.EmojiLightbulb,
48+
output.StyleItalic,
49+
"Indexed compressed (%.2fMB -> %.2fMB).",
50+
float64(originalSize)/1000/1000,
51+
float64(compressedSize)/1000/1000,
52+
))
53+
}
54+
55+
return UploadCompressedIndex(ctx, compressedFile, httpClient, opts, originalSize)
56+
}
57+
58+
func UploadCompressedIndex(ctx context.Context, compressedFile string, httpClient upload.Client, opts upload.UploadOptions, uncompressedSize int64) (int, error) {
59+
compressedReader, compressedSize, err := openFileAndGetSize(compressedFile)
60+
if err != nil {
61+
// cleanup(err)
62+
return 0, err
63+
}
64+
defer func() {
65+
_ = compressedReader.Close()
66+
}()
67+
68+
if compressedSize <= opts.MaxPayloadSizeBytes {
69+
return uploadIndex(ctx, httpClient, opts, compressedReader, compressedSize, uncompressedSize)
70+
}
71+
72+
return uploadMultipartIndex(ctx, httpClient, opts, compressedReader, compressedSize, uncompressedSize)
73+
}
74+
75+
func getFileSize(filename string) (int64, error) {
76+
fileInfo, err := os.Stat(filename)
77+
if err != nil {
78+
return 1, err
79+
}
80+
81+
return fileInfo.Size(), nil
82+
}

0 commit comments

Comments
 (0)