Skip to content

Commit 79348da

Browse files
authored
Merge branch 'master' into backoff
2 parents 9dda97b + 78c05df commit 79348da

File tree

5 files changed

+302
-96
lines changed

5 files changed

+302
-96
lines changed

cmd/download-crdb-binaries/main.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2025 The Cockroach Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
// implied. See the License for the specific language governing
13+
// permissions and limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"flag"
19+
"fmt"
20+
"log"
21+
"os"
22+
"runtime"
23+
24+
"github.com/cockroachdb/cockroach-go/v2/testserver"
25+
)
26+
27+
func main() {
28+
var (
29+
platform = flag.String("platform", runtime.GOOS, "Target platform (linux, darwin, windows)")
30+
arch = flag.String("arch", runtime.GOARCH, "Target architecture (amd64, arm64)")
31+
version = flag.String("version", "unstable", "CockroachDB version to download (use 'unstable' for latest bleeding edge, or specify version like 'v23.1.0')")
32+
output = flag.String("output", "", "Output directory (defaults to temp directory)")
33+
help = flag.Bool("help", false, "Show help")
34+
)
35+
36+
flag.Parse()
37+
38+
if *help {
39+
fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\n", os.Args[0])
40+
fmt.Fprintf(os.Stderr, "Download and extract CockroachDB binaries for specified platform and architecture.\n\n")
41+
fmt.Fprintf(os.Stderr, "Options:\n")
42+
flag.PrintDefaults()
43+
fmt.Fprintf(os.Stderr, "\nSupported platforms: linux, darwin, windows\n")
44+
fmt.Fprintf(os.Stderr, "Supported architectures: amd64, arm64\n")
45+
fmt.Fprintf(os.Stderr, "\nExamples:\n")
46+
fmt.Fprintf(os.Stderr, " %s -platform=linux -arch=amd64 -version=v23.1.0\n", os.Args[0])
47+
fmt.Fprintf(os.Stderr, " %s -platform=darwin -arch=arm64\n", os.Args[0])
48+
fmt.Fprintf(os.Stderr, " %s -platform=linux -arch=amd64 -version=unstable\n", os.Args[0])
49+
os.Exit(0)
50+
}
51+
52+
// Validate platform
53+
switch *platform {
54+
case "linux", "darwin", "windows":
55+
// Valid platforms
56+
default:
57+
log.Fatalf("Unsupported platform: %s. Supported platforms: linux, darwin, windows", *platform)
58+
}
59+
60+
// Validate architecture
61+
switch *arch {
62+
case "amd64", "arm64":
63+
// Valid architectures
64+
default:
65+
log.Fatalf("Unsupported architecture: %s. Supported architectures: amd64, arm64", *arch)
66+
}
67+
68+
// Special case: Windows only supports amd64
69+
if *platform == "windows" && *arch != "amd64" {
70+
log.Fatalf("Windows platform only supports amd64 architecture")
71+
}
72+
73+
fmt.Printf("Downloading CockroachDB binary for %s-%s", *platform, *arch)
74+
75+
var actualVersion string
76+
var nonStable bool
77+
78+
if *version == "unstable" {
79+
fmt.Printf(" (latest unstable)")
80+
actualVersion = ""
81+
nonStable = true
82+
} else {
83+
fmt.Printf(" version %s", *version)
84+
actualVersion = *version
85+
nonStable = false
86+
}
87+
fmt.Printf("\n")
88+
89+
// Download the binary
90+
binaryPath, err := testserver.DownloadBinaryWithPlatform(
91+
&testserver.TestConfig{},
92+
actualVersion,
93+
nonStable,
94+
*platform,
95+
*arch,
96+
*output,
97+
)
98+
if err != nil {
99+
log.Fatalf("Failed to download binary: %v", err)
100+
}
101+
102+
fmt.Printf("Successfully downloaded CockroachDB binary to: %s\n", binaryPath)
103+
}

testserver/binaries.go

Lines changed: 75 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@ import (
2626
"net/http"
2727
"net/url"
2828
"os"
29-
"os/exec"
3029
"path"
3130
"path/filepath"
32-
"regexp"
3331
"runtime"
3432
"strings"
3533
"time"
@@ -41,8 +39,8 @@ import (
4139

4240
const (
4341
latestSuffix = "LATEST"
44-
finishedFileMode = 0555
45-
writingFileMode = 0600 // Allow reads so that another process can check if there's a flock.
42+
finishedFileMode = 0o555
43+
writingFileMode = 0o600 // Allow reads so that another process can check if there's a flock.
4644
)
4745

4846
const (
@@ -58,39 +56,42 @@ const (
5856
// for testing purposes.
5957
const releaseDataURL = "https://raw.githubusercontent.com/cockroachdb/docs/main/src/current/_data/releases.yml"
6058

61-
var muslRE = regexp.MustCompile(`(?i)\bmusl\b`)
62-
6359
// GetDownloadURL returns the URL of a CRDB download. It creates the URL for
6460
// downloading a CRDB binary for current runtime OS. If desiredVersion is
6561
// specified, it will return the URL of the specified version. Otherwise, it
6662
// will return the URL of the latest stable cockroach binary. If nonStable is
6763
// true, the latest cockroach binary will be used.
6864
func GetDownloadURL(desiredVersion string, nonStable bool) (string, string, error) {
69-
goos := runtime.GOOS
70-
if goos == "linux" {
71-
goos += func() string {
72-
// Detect which C library is present on the system. See
73-
// https://unix.stackexchange.com/a/120381.
74-
cmd := exec.Command("ldd", "--version")
75-
out, err := cmd.Output()
76-
if err != nil {
77-
log.Printf("%s: %s: out=%q err=%v", testserverMessagePrefix, cmd.Args, out, err)
78-
} else if muslRE.Match(out) {
79-
return "-musl"
80-
}
81-
return "-gnu"
82-
}()
65+
return GetDownloadURLWithPlatform(desiredVersion, nonStable, runtime.GOOS, runtime.GOARCH)
66+
}
67+
68+
// GetDownloadURLWithPlatform returns the URL of a CRDB download for the specified
69+
// platform and architecture. If desiredVersion is specified, it will return the URL
70+
// of the specified version. Otherwise, it will return the URL of the latest stable
71+
// cockroach binary. If nonStable is true, the latest cockroach binary will be used.
72+
func GetDownloadURLWithPlatform(
73+
desiredVersion string, nonStable bool, goos, goarch string,
74+
) (string, string, error) {
75+
targetGoos := goos
76+
if targetGoos == "linux" {
77+
targetGoos += "-gnu"
78+
}
79+
// For unstable builds, macOS ARM64 binaries have ".unsigned" at the end
80+
var binaryName string
81+
if nonStable && goos == "darwin" && goarch == "arm64" {
82+
binaryName = fmt.Sprintf("cockroach.%s-%s.unsigned", targetGoos, goarch)
83+
} else {
84+
binaryName = fmt.Sprintf("cockroach.%s-%s", targetGoos, goarch)
8385
}
84-
binaryName := fmt.Sprintf("cockroach.%s-%s", goos, runtime.GOARCH)
85-
if runtime.GOOS == "windows" {
86+
if goos == "windows" {
8687
binaryName += ".exe"
8788
}
8889

8990
var dbUrl string
9091
var err error
9192

9293
if desiredVersion != "" {
93-
dbUrl = getDownloadUrlForVersion(desiredVersion)
94+
dbUrl = getDownloadUrlForVersionWithPlatform(desiredVersion, goos, goarch)
9495
} else if nonStable {
9596
// For the latest (beta) CRDB, we use the `edge-binaries.cockroachdb.com` host.
9697
u := &url.URL{
@@ -137,16 +138,46 @@ func DownloadFromURL(downloadURL string) (*http.Response, error) {
137138
// To download the latest STABLE version of CRDB, set `nonStable` to false.
138139
// To download the bleeding edge version of CRDB, set `nonStable` to true.
139140
func DownloadBinary(tc *TestConfig, desiredVersion string, nonStable bool) (string, error) {
140-
dbUrl, desiredVersion, err := GetDownloadURL(desiredVersion, nonStable)
141+
return DownloadBinaryWithPlatform(tc, desiredVersion, nonStable, runtime.GOOS, runtime.GOARCH, "")
142+
}
143+
144+
// DownloadBinaryWithPlatform saves the specified version of CRDB for the given
145+
// platform and architecture into a local binary file, and returns the path for
146+
// this local binary.
147+
// To download a specific cockroach version, specify desiredVersion. Otherwise,
148+
// the latest stable or non-stable version will be chosen.
149+
// To download the latest STABLE version of CRDB, set `nonStable` to false.
150+
// To download the bleeding edge version of CRDB, set `nonStable` to true.
151+
// If outputDir is specified, the binary will be saved there, otherwise to temp directory.
152+
func DownloadBinaryWithPlatform(
153+
tc *TestConfig, desiredVersion string, nonStable bool, goos, goarch, outputDir string,
154+
) (string, error) {
155+
dbUrl, desiredVersion, err := GetDownloadURLWithPlatform(desiredVersion, nonStable, goos, goarch)
141156
if err != nil {
142157
return "", err
143158
}
144159

145-
filename, err := GetDownloadFilename(desiredVersion)
160+
// For unstable builds, use "latest" as the version for filename generation
161+
filenameVersion := desiredVersion
162+
if nonStable && desiredVersion == "" {
163+
filenameVersion = "latest"
164+
}
165+
166+
filename, err := GetDownloadFilenameWithPlatform(filenameVersion, goos)
146167
if err != nil {
147168
return "", err
148169
}
149-
localFile := filepath.Join(os.TempDir(), filename)
170+
171+
var localFile string
172+
if outputDir != "" {
173+
// Create output directory if it doesn't exist
174+
if err := os.MkdirAll(outputDir, 0o755); err != nil {
175+
return "", fmt.Errorf("failed to create output directory %s: %w", outputDir, err)
176+
}
177+
localFile = filepath.Join(outputDir, filename)
178+
} else {
179+
localFile = filepath.Join(os.TempDir(), filename)
180+
}
150181

151182
// Short circuit if the file already exists and is in the finished state.
152183
info, err := os.Stat(localFile)
@@ -224,7 +255,7 @@ func DownloadBinary(tc *TestConfig, desiredVersion string, nonStable bool) (stri
224255
if nonStable {
225256
downloadMethod = downloadBinaryFromResponse
226257
} else {
227-
if runtime.GOOS == "windows" {
258+
if goos == "windows" {
228259
downloadMethod = downloadBinaryFromZip
229260
} else {
230261
downloadMethod = downloadBinaryFromTar
@@ -253,8 +284,14 @@ func DownloadBinary(tc *TestConfig, desiredVersion string, nonStable bool) (stri
253284

254285
// GetDownloadFilename returns the local filename of the downloaded CRDB binary file.
255286
func GetDownloadFilename(desiredVersion string) (string, error) {
287+
return GetDownloadFilenameWithPlatform(desiredVersion, runtime.GOOS)
288+
}
289+
290+
// GetDownloadFilenameWithPlatform returns the local filename of the downloaded CRDB binary file
291+
// for the specified platform.
292+
func GetDownloadFilenameWithPlatform(desiredVersion, goos string) (string, error) {
256293
filename := fmt.Sprintf("cockroach-%s", desiredVersion)
257-
if runtime.GOOS == "windows" {
294+
if goos == "windows" {
258295
filename += ".exe"
259296
}
260297
return filename, nil
@@ -320,28 +357,28 @@ func getLatestStableVersionInfo() (string, string, error) {
320357
}
321358
}
322359

323-
downloadUrl := getDownloadUrlForVersion(latestStableVersion.String())
360+
downloadUrl := getDownloadUrlForVersionWithPlatform(latestStableVersion.String(), runtime.GOOS, runtime.GOARCH)
324361

325362
latestStableVerFormatted := strings.ReplaceAll(latestStableVersion.String(), ".", "-")
326363
return downloadUrl, latestStableVerFormatted, nil
327364
}
328365

329-
func getDownloadUrlForVersion(version string) string {
330-
switch runtime.GOOS {
366+
func getDownloadUrlForVersionWithPlatform(version, goos, goarch string) string {
367+
switch goos {
331368
case "linux":
332-
return fmt.Sprintf(linuxUrlpat, version, runtime.GOARCH)
369+
return fmt.Sprintf(linuxUrlpat, version, goarch)
333370
case "darwin":
334-
switch runtime.GOARCH {
371+
switch goarch {
335372
case "arm64":
336-
return fmt.Sprintf(macUrlpat, version, "11.0", runtime.GOARCH)
373+
return fmt.Sprintf(macUrlpat, version, "11.0", goarch)
337374
case "amd64":
338-
return fmt.Sprintf(macUrlpat, version, "10.9", runtime.GOARCH)
375+
return fmt.Sprintf(macUrlpat, version, "10.9", goarch)
339376
}
340377
case "windows":
341378
return fmt.Sprintf(winUrlpat, version)
342379
}
343380

344-
panic(errors.New("could not get supported go os version"))
381+
panic(fmt.Errorf("unsupported platform/architecture combination: %s-%s", goos, goarch))
345382
}
346383

347384
// downloadBinaryFromResponse copies the http response's body directly into a local binary.
@@ -403,7 +440,8 @@ func downloadBinaryFromTar(response *http.Response, output *os.File, filePath st
403440
}
404441

405442
}
406-
return nil
443+
// Unreachable, but left present for safety in case later changes make this branch reachable again.
444+
return fmt.Errorf("could not find cockroach binary in archive")
407445
}
408446

409447
// downloadBinaryFromZip writes the binary compressed in a zip from a http response

0 commit comments

Comments
 (0)