From b1401b8b4f31e5433792958669ffc4ed1e9ea983 Mon Sep 17 00:00:00 2001 From: Marin Nozhchev Date: Tue, 16 Sep 2025 17:25:44 +0300 Subject: [PATCH 1/4] feat: download preview releases --- download/download.go | 1 - download/preview.go | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 download/preview.go diff --git a/download/download.go b/download/download.go index 39add2b..8f6ee68 100644 --- a/download/download.go +++ b/download/download.go @@ -12,7 +12,6 @@ import ( "strings" "github.com/ansel1/merry/v2" - "golang.org/x/mod/semver" "github.com/murfffi/getaduck/internal/sclerr" ) diff --git a/download/preview.go b/download/preview.go new file mode 100644 index 0000000..4d3c673 --- /dev/null +++ b/download/preview.go @@ -0,0 +1,7 @@ +package download + +import "errors" + +func fetchPreview(spec Spec) (string, error) { + return "", errors.New("not implemented") +} From 4bc8a8081ff3226a8addba3b3680dcc693c79612 Mon Sep 17 00:00:00 2001 From: Marin Nozhchev Date: Sun, 28 Sep 2025 10:31:51 +0300 Subject: [PATCH 2/4] fixup --- .gitignore | 3 ++- go.mod | 1 - go.sum | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 616978e..d1dee63 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ go.work.sum # env file .env -.idea \ No newline at end of file +.idea +/duckdb diff --git a/go.mod b/go.mod index b3dd233..64ed386 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,5 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/mod v0.28.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b1ca6e8..5395190 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From b906771f425050c1399d3744beea1d95fdbc4103 Mon Sep 17 00:00:00 2001 From: Marin Nozhchev Date: Sun, 28 Sep 2025 11:08:39 +0300 Subject: [PATCH 3/4] complete --- download/download.go | 19 +++++++++++++-- download/download_test.go | 1 + download/preview.go | 50 ++++++++++++++++++++++++++++++++++++--- go.mod | 1 + go.sum | 2 ++ 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/download/download.go b/download/download.go index 8f6ee68..0c661e2 100644 --- a/download/download.go +++ b/download/download.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/ansel1/merry/v2" + "golang.org/x/mod/semver" "github.com/murfffi/getaduck/internal/sclerr" ) @@ -75,7 +76,7 @@ func Do(spec Spec) (Result, error) { return res, nil } res.Downloaded = true - path := getGithubURL(spec) + path := getZipDownloadUrl(spec) tmpFile, err := fetchZip(path) if err != nil { return res, err @@ -83,7 +84,21 @@ func Do(spec Spec) (Result, error) { defer func() { _ = os.Remove(tmpFile) }() - return res, extractOne(tmpFile, entryName) + return res, processZip(spec, entryName, tmpFile) +} + +func processZip(spec Spec, entryName string, zipFile string) error { + if spec.Version != PreviewVersion { + return extractOne(zipFile, entryName) + } + return processPreviewZip(spec, entryName, zipFile) +} + +func getZipDownloadUrl(spec Spec) string { + if spec.Version == PreviewVersion { + return getPreviewZipUrl(spec) + } + return getGithubURL(spec) } func existsAppropriate(fileName string) bool { diff --git a/download/download_test.go b/download/download_test.go index 4110612..b9084ae 100644 --- a/download/download_test.go +++ b/download/download_test.go @@ -17,6 +17,7 @@ func TestDo(t *testing.T) { "v1.3.2", "v1.4.0", "latest", + "preview", } { t.Run(version, func(t *testing.T) { for _, arch := range []string{ diff --git a/download/preview.go b/download/preview.go index 4d3c673..bff6592 100644 --- a/download/preview.go +++ b/download/preview.go @@ -1,7 +1,51 @@ package download -import "errors" +import ( + "fmt" + "os" +) -func fetchPreview(spec Spec) (string, error) { - return "", errors.New("not implemented") +const ( + PreviewVersion = "preview" +) + +func getPreviewZipUrl(spec Spec) string { + // https://artifacts.duckdb.org/latest/duckdb-binaries-osx.zip + // https://artifacts.duckdb.org/latest/duckdb-binaries-windows.zip + // https://artifacts.duckdb.org/latest/duckdb-binaries-linux-amd64.zip + archSuffix := "" + if spec.OS == "linux" { + archSuffix = "-" + spec.Arch + } + return fmt.Sprintf("https://artifacts.duckdb.org/latest/duckdb-binaries-%s%s.zip", spec.OS, archSuffix) +} + +func processPreviewZip(spec Spec, entryName string, zipFile string) error { + innerZip := getInnerZipName(spec) + err := extractOne(zipFile, innerZip) + if err != nil { + return err + } + defer func() { + _ = os.Remove(innerZip) + }() + return extractOne(innerZip, entryName) +} + +func getInnerZipName(spec Spec) string { + // duckdb_cli-osx-universal.zip + // libduckdb-osx-universal.zip + // duckdb_cli-windows-arm64.zip + // libduckdb-windows-amd64.zip + // duckdb_cli-linux-amd64.zip + // libduckdb-linux-amd64.zip + prefix := "" + switch spec.Type { + case BinTypeCli: + prefix = "duckdb_cli" + case BinTypeDynLib: + prefix = "libduckdb" + } + // For osx, spec.Arch has been normalized to universal in normalizeSpec + return fmt.Sprintf("%s-%s-%s.zip", prefix, spec.OS, spec.Arch) } diff --git a/go.mod b/go.mod index 64ed386..4877963 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.7 require ( github.com/ansel1/merry/v2 v2.2.1 github.com/stretchr/testify v1.8.3 + golang.org/x/mod v0.28.0 ) require ( diff --git a/go.sum b/go.sum index 5395190..b1ca6e8 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 46da50bb104e521d59a8d365d23e30fd980d1e0c Mon Sep 17 00:00:00 2001 From: Marin Nozhchev Date: Sun, 28 Sep 2025 13:05:48 +0300 Subject: [PATCH 4/4] fixup --- .gitignore | 4 +++- download/download.go | 15 ++++++++++----- download/preview.go | 18 +++++++++--------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index d1dee63..38b3c31 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ go.work.sum .env .idea -/duckdb +duckdb +duckdb.exe + diff --git a/download/download.go b/download/download.go index 0c661e2..b9c09b0 100644 --- a/download/download.go +++ b/download/download.go @@ -109,16 +109,21 @@ func existsAppropriate(fileName string) bool { } func getGithubURL(spec Spec) string { - var archivePrefix string - switch spec.Type { + archivePrefix := getPrefixByType(spec.Type) + return fmt.Sprintf("%s/download/%s/%s-%s-%s.zip", duckDbReleasesRoot, spec.Version, archivePrefix, spec.OS, spec.Arch) +} + +func getPrefixByType(typ BinType) string { + var prefix string + switch typ { case BinTypeCli: - archivePrefix = "duckdb_cli" + prefix = "duckdb_cli" case BinTypeDynLib: - archivePrefix = "libduckdb" + prefix = "libduckdb" default: panic("unhandled spec type") } - return fmt.Sprintf("%s/download/%s/%s-%s-%s.zip", duckDbReleasesRoot, spec.Version, archivePrefix, spec.OS, spec.Arch) + return prefix } func normalizeSpec(spec Spec) (Spec, error) { diff --git a/download/preview.go b/download/preview.go index bff6592..3334d39 100644 --- a/download/preview.go +++ b/download/preview.go @@ -3,6 +3,8 @@ package download import ( "fmt" "os" + + "github.com/ansel1/merry/v2" ) const ( @@ -24,12 +26,16 @@ func processPreviewZip(spec Spec, entryName string, zipFile string) error { innerZip := getInnerZipName(spec) err := extractOne(zipFile, innerZip) if err != nil { - return err + return merry.Wrap(fmt.Errorf("failed to extract inner zip '%s' from '%s': %w", innerZip, zipFile, err)) } defer func() { _ = os.Remove(innerZip) }() - return extractOne(innerZip, entryName) + err = extractOne(innerZip, entryName) + if err != nil { + return merry.Wrap(fmt.Errorf("failed to extract entry '%s' from inner zip '%s': %w", entryName, innerZip, err)) + } + return nil } func getInnerZipName(spec Spec) string { @@ -39,13 +45,7 @@ func getInnerZipName(spec Spec) string { // libduckdb-windows-amd64.zip // duckdb_cli-linux-amd64.zip // libduckdb-linux-amd64.zip - prefix := "" - switch spec.Type { - case BinTypeCli: - prefix = "duckdb_cli" - case BinTypeDynLib: - prefix = "libduckdb" - } + prefix := getPrefixByType(spec.Type) // For osx, spec.Arch has been normalized to universal in normalizeSpec return fmt.Sprintf("%s-%s-%s.zip", prefix, spec.OS, spec.Arch) }