snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
This commit is contained in:
136
internal/goldeneye/duckdb/install.go
Normal file
136
internal/goldeneye/duckdb/install.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package duckdb
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DefaultVersion is the DuckDB preview channel the CLI is downloaded from:
|
||||
// the v2.0 development builds, which DuckDB publishes as a rolling tarball
|
||||
// per platform under https://artifacts.duckdb.org/<channel>/ until 2.0 is
|
||||
// released. A channel has no per-build download and no checksum to pin,
|
||||
// so Install fetches whatever build the channel holds and the version the
|
||||
// CLI reports is what a run logs; GeneratedFrom records the build the
|
||||
// committed dialect came from, and a check against a later build reports
|
||||
// what the later build added. Once 2.0 is released, pin the release and
|
||||
// its checksums here the way the clickhouse package does.
|
||||
const DefaultVersion = "v2.0-cyanoptera"
|
||||
|
||||
// GeneratedFrom is the build the committed dialect was generated from, as
|
||||
// `duckdb --version` reports it. Update it when regenerating.
|
||||
const GeneratedFrom = "v2.0.0-alpha41396 (Cyanoptera) d41e527b18"
|
||||
|
||||
// channelURL is the download address of a channel's CLI tarball for a
|
||||
// platform. DuckDB publishes one macOS build for both architectures.
|
||||
func channelURL(channel, goos, goarch string) (string, error) {
|
||||
var name string
|
||||
switch {
|
||||
case goos == "linux" && (goarch == "amd64" || goarch == "arm64"):
|
||||
name = "duckdb-cli-linux-" + goarch + ".tar.gz"
|
||||
case goos == "darwin":
|
||||
name = "duckdb-cli-osx-universal.tar.gz"
|
||||
default:
|
||||
return "", fmt.Errorf("no DuckDB %s build is published for %s/%s", channel, goos, goarch)
|
||||
}
|
||||
return "https://artifacts.duckdb.org/" + channel + "/" + name, nil
|
||||
}
|
||||
|
||||
// cachedBinary is where Install puts the binary for a channel.
|
||||
func cachedBinary(channel string) (string, error) {
|
||||
dir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(dir, "sqlc-duckdb", channel, "duckdb"), nil
|
||||
}
|
||||
|
||||
// Install downloads the channel's current CLI into the cache and returns
|
||||
// its path. It is a no-op when the channel is already cached: remove the
|
||||
// cached directory to fetch the channel's newer build.
|
||||
func Install(ctx context.Context, channel, goos, goarch string, progress io.Writer) (string, error) {
|
||||
dest, err := cachedBinary(channel)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err := os.Stat(dest); err == nil {
|
||||
return dest, nil
|
||||
}
|
||||
url, err := channelURL(channel, goos, goarch)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
fmt.Fprintf(progress, "downloading %s\n", url)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("downloading %s: %s", url, resp.Status)
|
||||
}
|
||||
|
||||
// Write next to the destination and rename so a partial download never
|
||||
// masquerades as an installed binary.
|
||||
tmp, err := os.CreateTemp(filepath.Dir(dest), "duckdb-*.partial")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer os.Remove(tmp.Name())
|
||||
src, err := binaryInTarball(resp.Body)
|
||||
if err != nil {
|
||||
tmp.Close()
|
||||
return "", fmt.Errorf("downloading %s: %w", url, err)
|
||||
}
|
||||
if _, err := io.Copy(tmp, src); err != nil {
|
||||
tmp.Close()
|
||||
return "", err
|
||||
}
|
||||
if err := tmp.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.Chmod(tmp.Name(), 0o755); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.Rename(tmp.Name(), dest); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return dest, nil
|
||||
}
|
||||
|
||||
// binaryInTarball positions a reader at the duckdb binary inside a CLI
|
||||
// tarball, which holds it at the top level.
|
||||
func binaryInTarball(r io.Reader) (io.Reader, error) {
|
||||
gz, err := gzip.NewReader(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tr := tar.NewReader(gz)
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
return nil, errors.New("tarball does not contain duckdb")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hdr.Typeflag == tar.TypeReg && strings.TrimPrefix(hdr.Name, "./") == "duckdb" {
|
||||
return tr, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user