Skip to content

Commit 9d674ef

Browse files
committed
feat: Self upgrade from metadata
1 parent 3eeb770 commit 9d674ef

3 files changed

Lines changed: 22 additions & 123 deletions

File tree

cmd/uniget/self-upgrade.go

Lines changed: 22 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,21 @@
11
package main
22

33
import (
4-
"context"
54
"fmt"
6-
"io"
7-
"net/http"
85
"os"
96
"os/exec"
107
"path/filepath"
11-
"regexp"
12-
"runtime"
13-
"sort"
148

15-
"github.com/google/go-github/github"
169
"github.com/google/safearchive/tar"
17-
goversion "github.com/hashicorp/go-version"
1810
"github.com/spf13/cobra"
1911

2012
"github.com/uniget-org/cli/pkg/archive"
13+
"github.com/uniget-org/cli/pkg/containers"
2114
"github.com/uniget-org/cli/pkg/logging"
2215
)
2316

24-
var requestedVersion string
25-
var allowPrereleaseVersion bool
26-
var dryRun bool
27-
2817
func initSelfUpgradeCmd() {
2918
rootCmd.AddCommand(selfUpgradeCmd)
30-
31-
selfUpgradeCmd.Flags().StringVar(&requestedVersion, "version", "latest", "Upgrade to a specific version")
32-
selfUpgradeCmd.Flags().BoolVar(&allowPrereleaseVersion, "allow-prerelease", false, "Allow upgrading to prerelease version")
33-
selfUpgradeCmd.Flags().BoolVar(&dryRun, "dry-run", false, "Do not perform the upgrade, only show what would be done")
3419
}
3520

3621
var selfUpgradeCmd = &cobra.Command{
@@ -39,12 +24,20 @@ var selfUpgradeCmd = &cobra.Command{
3924
Long: header + "\nUpgrade " + projectName + " to latest version",
4025
Args: cobra.NoArgs,
4126
RunE: func(cmd *cobra.Command, args []string) error {
42-
versionRegex, err := regexp.Compile(`^\d+\.\d+\.\d+(-[a-z]+\.\d+)?$`)
27+
err := downloadMetadata()
4328
if err != nil {
44-
return fmt.Errorf("cannot compile regexp: %w", err)
29+
return fmt.Errorf("error downloading metadata: %s", err)
4530
}
46-
if !versionRegex.MatchString(version) {
47-
return fmt.Errorf("invalid version %s", version)
31+
assertMetadataFileExists()
32+
assertMetadataIsLoaded()
33+
err = loadMetadata()
34+
if err != nil {
35+
return fmt.Errorf("error loading metadata: %s", err)
36+
}
37+
38+
unigetTool, err := tools.GetByName("uniget")
39+
if err != nil {
40+
return fmt.Errorf("failed to get uniget tool: %s", err)
4841
}
4942

5043
selfExe := filepath.Base(os.Args[0])
@@ -64,69 +57,7 @@ var selfUpgradeCmd = &cobra.Command{
6457
logging.Debugf("%s is available at %s\n", selfExe, path)
6558
selfDir := filepath.Dir(path)
6659

67-
if allowPrereleaseVersion && requestedVersion == "latest" {
68-
logging.Debugf("Allowing prerelease version")
69-
70-
githubClient := github.NewClient(nil)
71-
releases, _, err := githubClient.Repositories.ListReleases(context.Background(), githubOrganization, "cli", &github.ListOptions{PerPage: 100})
72-
if err != nil {
73-
return fmt.Errorf("failed to list releases: %s", err)
74-
}
75-
76-
versions := make([]*goversion.Version, 0)
77-
for _, release := range releases {
78-
version, err := goversion.NewSemver(*release.TagName)
79-
if err != nil {
80-
continue
81-
}
82-
83-
versions = append(versions, version)
84-
sort.Sort(goversion.Collection(versions))
85-
}
86-
requestedVersion = versions[len(versions)-1].String()
87-
}
88-
89-
var url string
90-
if requestedVersion == "latest" {
91-
url = fmt.Sprintf("https://github.com/%s/releases/%s/download/uniget_%s_%s.tar.gz", projectRepository, requestedVersion, runtime.GOOS, arch)
92-
} else {
93-
logging.Info.Printfln("Requested version %s", requestedVersion)
94-
url = fmt.Sprintf("https://github.com/%s/releases/download/v%s/uniget_%s_%s.tar.gz", projectRepository, requestedVersion, runtime.GOOS, arch)
95-
}
96-
97-
logging.Debugf("Downloading from %s", url)
98-
if dryRun {
99-
logging.Info.Printfln("Would download version %s from %s", requestedVersion, url)
100-
return nil
101-
}
102-
103-
resp, err := downloadReleaseAsset(url)
104-
if err != nil {
105-
return fmt.Errorf("failed to download %s: %s", url, err)
106-
}
107-
defer func() {
108-
err := resp.Body.Close()
109-
if err != nil {
110-
logging.Warning.Printfln("failed to close response body: %s", err)
111-
}
112-
}()
113-
114-
if resp.StatusCode != 200 {
115-
return fmt.Errorf("failed to download %s: %s", url, resp.Status)
116-
}
117-
118-
requestedVersionVersion, err := goversion.NewVersion(requestedVersion)
119-
if err != nil {
120-
return fmt.Errorf("failed to parse version %s: %s", requestedVersion, err)
121-
}
122-
versionVersion, err := goversion.NewVersion(version)
123-
if err != nil {
124-
return fmt.Errorf("failed to parse current version %s: %s", version, err)
125-
}
126-
if requestedVersionVersion.LessThanOrEqual(versionVersion) {
127-
logging.Info.Printfln("Latest version %s already installed.", version)
128-
return nil
129-
}
60+
logging.Info.Printfln("Installing version %s", unigetTool.Version)
13061

13162
logging.Debugf("Extracting tar.gz")
13263
err = os.Chdir(selfDir)
@@ -138,15 +69,18 @@ var selfUpgradeCmd = &cobra.Command{
13869
return fmt.Errorf("failed to remove %s: %s", selfExe, err)
13970
}
14071

141-
bodyGz, err := io.ReadAll(resp.Body)
72+
registries, repositories := unigetTool.GetSourcesWithFallback(registry, imageRepository)
73+
ref, err := containers.FindToolRef(registries, repositories, unigetTool.Name, "main")
14274
if err != nil {
143-
return fmt.Errorf("failed to read body: %s", err)
75+
return fmt.Errorf("error finding tool %s:%s: %s", unigetTool.Name, unigetTool.Version, err)
14476
}
145-
body, err := archive.Gunzip(bodyGz)
77+
logging.Debugf("Getting image %s", ref)
78+
layer, err := toolCache.Get(ref)
14679
if err != nil {
147-
return fmt.Errorf("failed to gunzip body: %s", err)
80+
return fmt.Errorf("unable to get image: %s", err)
14881
}
149-
err = archive.ProcessTarContents(body, func(tar *tar.Reader, header *tar.Header) error {
82+
83+
err = archive.ProcessTarContents(layer, func(tar *tar.Reader, header *tar.Header) error {
15084
if header.Name == "uniget" {
15185
logging.Debugf("Extracting %s", header.Name)
15286
err := archive.CallbackExtractTarItem(tar, header)
@@ -161,34 +95,6 @@ var selfUpgradeCmd = &cobra.Command{
16195
return fmt.Errorf("failed to extract tar.gz: %s", err)
16296
}
16397

164-
logging.Info.Printfln("Upgraded to version %s", requestedVersion)
16598
return nil
16699
},
167100
}
168-
169-
func downloadReleaseAsset(url string) (*http.Response, error) {
170-
client := &http.Client{
171-
CheckRedirect: func(req *http.Request, via []*http.Request) error {
172-
re, err := regexp.Compile(`\/uniget-org\/cli\/releases\/download\/(v\d+\.\d+\.\d+)\/`)
173-
if err != nil {
174-
return fmt.Errorf("cannot compile regexp: %w", err)
175-
}
176-
177-
if re.MatchString(req.URL.Path) {
178-
requestedVersion = re.FindStringSubmatch(req.URL.Path)[1]
179-
}
180-
return nil
181-
},
182-
}
183-
req, err := http.NewRequest("GET", url, nil)
184-
if err != nil {
185-
return nil, fmt.Errorf("failed to create request: %s", err)
186-
}
187-
req.Header.Set("Accept", "application/octet-stream")
188-
req.Header.Set("User-Agent", fmt.Sprintf("%s/%s", projectName, version))
189-
resp, err := client.Do(req)
190-
if err != nil {
191-
return nil, fmt.Errorf("failed to download %s: %s", url, err)
192-
}
193-
return resp, nil
194-
}

go.mod

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ require (
1010
github.com/containerd/platforms v1.0.0-rc.1
1111
github.com/distribution/distribution/v3 v3.0.0
1212
github.com/docker/docker v28.3.2+incompatible
13-
github.com/google/go-github v17.0.0+incompatible
1413
github.com/google/safearchive v0.0.0-20241025131057-f7ce9d7b6f9c
1514
github.com/google/safeopen v0.0.0-20240125081138-66b54d5181c6
1615
github.com/hashicorp/go-version v1.7.0
@@ -75,7 +74,6 @@ require (
7574
github.com/gogo/protobuf v1.3.2 // indirect
7675
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
7776
github.com/google/go-cmp v0.7.0 // indirect
78-
github.com/google/go-querystring v1.1.0 // indirect
7977
github.com/google/uuid v1.6.0 // indirect
8078
github.com/gookit/color v1.5.4 // indirect
8179
github.com/gorilla/css v1.0.1 // indirect

go.sum

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,9 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
175175
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
176176
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
177177
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
178-
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
179178
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
180179
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
181180
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
182-
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
183-
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
184-
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
185-
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
186181
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
187182
github.com/google/safearchive v0.0.0-20241025131057-f7ce9d7b6f9c h1:GzqKebXGmQ+9RUwNUCjt768fVW0mMkSjw+BTR7wlyLQ=
188183
github.com/google/safearchive v0.0.0-20241025131057-f7ce9d7b6f9c/go.mod h1:OqnQPv70Lm5prPo201C0t0krFmSjwgcWIAsA9S0xdQA=

0 commit comments

Comments
 (0)