Skip to content

Commit 1e69751

Browse files
committed
Add targeted support for bine upgrade
1 parent d50200e commit 1e69751

5 files changed

Lines changed: 158 additions & 11 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ SUBCOMMANDS
206206
path Print the path of the binary store.
207207
run Download a binary and run it.
208208
sync Install all binaries defined in the configuration file.
209-
upgrade Upgrade all binaries defined in the configuration file.
209+
upgrade Upgrade binaries defined in the configuration file.
210210
version Print the current version of bine.
211211
212212
FLAGS

‎bine/bine.go‎

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,8 @@ func (b *Bine) Run(ctx context.Context, name string, args []string, streams IOSt
453453
return nil
454454
}
455455

456-
// Sync installs all binaries defined in the configuration.
457-
func (b *Bine) Sync(ctx context.Context) error {
458-
for _, item := range b.config.Bins {
456+
func (b *Bine) syncBins(ctx context.Context, bins []*bin) error {
457+
for _, item := range bins {
459458
bin, err := b.load(item.Name)
460459
if err != nil {
461460
return fmt.Errorf("sync: %v", err)
@@ -470,8 +469,37 @@ func (b *Bine) Sync(ctx context.Context) error {
470469
return nil
471470
}
472471

472+
// Sync installs all binaries defined in the configuration.
473+
func (b *Bine) Sync(ctx context.Context) error {
474+
return b.syncBins(ctx, b.config.Bins)
475+
}
476+
473477
func (b *Bine) Upgrade(ctx context.Context) ([]*ListItem, error) {
474-
updates, err := b.List(ctx, false, true)
478+
return b.upgradeBins(ctx, b.config.Bins)
479+
}
480+
481+
// UpgradeOne upgrades a single binary defined in the configuration.
482+
func (b *Bine) UpgradeOne(ctx context.Context, name string) ([]*ListItem, error) {
483+
selected, err := b.load(name)
484+
if err != nil {
485+
return nil, fmt.Errorf("upgrade: %v", err)
486+
}
487+
488+
return b.upgradeBins(ctx, []*bin{selected})
489+
}
490+
491+
// ListOne returns list information for a single binary defined in the configuration.
492+
func (b *Bine) ListOne(ctx context.Context, name string, installedOnly, outdatedOnly bool) ([]*ListItem, error) {
493+
selected, err := b.load(name)
494+
if err != nil {
495+
return nil, fmt.Errorf("list: %v", err)
496+
}
497+
498+
return b.listBins(ctx, []*bin{selected}, installedOnly, outdatedOnly)
499+
}
500+
501+
func (b *Bine) upgradeBins(ctx context.Context, bins []*bin) ([]*ListItem, error) {
502+
updates, err := b.listBins(ctx, bins, false, true)
475503
if err != nil {
476504
return nil, err
477505
}
@@ -502,7 +530,7 @@ func (b *Bine) Upgrade(ctx context.Context) ([]*ListItem, error) {
502530
}
503531
}
504532

505-
if err := b.Sync(ctx); err != nil {
533+
if err := b.syncBins(ctx, bins); err != nil {
506534
return updates, err
507535
}
508536

@@ -519,9 +547,13 @@ type ListItem struct {
519547
}
520548

521549
func (b *Bine) List(ctx context.Context, installedOnly, outdatedOnly bool) ([]*ListItem, error) {
550+
return b.listBins(ctx, b.config.Bins, installedOnly, outdatedOnly)
551+
}
552+
553+
func (b *Bine) listBins(ctx context.Context, bins []*bin, installedOnly, outdatedOnly bool) ([]*ListItem, error) {
522554
var items []*ListItem
523555

524-
for _, bin := range b.config.Bins {
556+
for _, bin := range bins {
525557
if installedOnly {
526558
ok, err := b.installed(ctx, bin)
527559
if err != nil {

‎bine/latest_test.go‎

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package bine
22

33
import (
44
"context"
5+
"errors"
56
"os"
67
"path/filepath"
78
"testing"
@@ -136,3 +137,91 @@ func TestUpgradeFailsSafelyWhenLatestMarkerCannotBeRemoved(t *testing.T) {
136137
_, statErr := os.Stat(binPath)
137138
assert.NilError(t, statErr)
138139
}
140+
141+
func TestListOneScopesOutdatedChecksToTargetBin(t *testing.T) {
142+
configPath := filepath.Join(t.TempDir(), ".bine.json")
143+
assert.NilError(t, os.WriteFile(configPath, []byte("{}"), 0o640))
144+
145+
b := &Bine{
146+
config: &config{
147+
path: configPath,
148+
Bins: []*bin{
149+
{
150+
Name: "broken",
151+
GoPackage: "github.com/foo/bar/cmd/broken",
152+
Version: "1.0.0",
153+
provider: staticProvider{err: errors.New("boom")},
154+
},
155+
{
156+
Name: "tool",
157+
GoPackage: "github.com/foo/bar/cmd/tool",
158+
Version: "1.0.0",
159+
provider: staticProvider{latest: "2.0.0"},
160+
},
161+
},
162+
},
163+
}
164+
165+
items, err := b.ListOne(t.Context(), "tool", false, true)
166+
assert.NilError(t, err)
167+
assert.Equal(t, len(items), 1)
168+
assert.Equal(t, items[0].Name, "tool")
169+
assert.Equal(t, items[0].Latest, "v2.0.0")
170+
}
171+
172+
func TestUpgradeOneOnlyUpdatesRequestedBin(t *testing.T) {
173+
injectFakeExec(t, "TestHelperProcessWithSuccess")
174+
175+
cacheDir := t.TempDir()
176+
configPath := filepath.Join(cacheDir, ".bine.json")
177+
assert.NilError(t, os.WriteFile(configPath, []byte(`{
178+
"project": "test",
179+
"bins": [
180+
{"name": "tool", "go_package": "github.com/foo/bar/cmd/tool", "version": "1.0.0"},
181+
{"name": "other", "go_package": "github.com/foo/bar/cmd/other", "version": "1.0.0"}
182+
]
183+
}`), 0o640))
184+
185+
b := &Bine{
186+
BinDir: filepath.Join(cacheDir, "bin"),
187+
VersionsDir: filepath.Join(cacheDir, "versions"),
188+
config: &config{
189+
path: configPath,
190+
Bins: []*bin{
191+
{
192+
Name: "tool",
193+
GoPackage: "github.com/foo/bar/cmd/tool",
194+
Version: "1.0.0",
195+
provider: staticProvider{latest: "2.0.0"},
196+
},
197+
{
198+
Name: "other",
199+
GoPackage: "github.com/foo/bar/cmd/other",
200+
Version: "1.0.0",
201+
provider: staticProvider{latest: "3.0.0"},
202+
},
203+
},
204+
},
205+
}
206+
207+
updates, err := b.UpgradeOne(t.Context(), "tool")
208+
assert.NilError(t, err)
209+
assert.Equal(t, len(updates), 1)
210+
assert.Equal(t, updates[0].Name, "tool")
211+
assert.Equal(t, updates[0].Latest, "v2.0.0")
212+
213+
configBlob, err := os.ReadFile(configPath)
214+
assert.NilError(t, err)
215+
assert.Equal(t, string(configBlob), `{
216+
"project": "test",
217+
"bins": [
218+
{"name": "tool", "go_package": "github.com/foo/bar/cmd/tool", "version": "2.0.0"},
219+
{"name": "other", "go_package": "github.com/foo/bar/cmd/other", "version": "1.0.0"}
220+
]
221+
}`)
222+
223+
_, err = os.Stat(filepath.Join(b.BinDir, "tool"))
224+
assert.NilError(t, err)
225+
_, err = os.Stat(filepath.Join(b.BinDir, "other"))
226+
assert.Assert(t, os.IsNotExist(err))
227+
}

‎cmd/upgradecmd/upgradecmd.go‎

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ func New(parent *rootcmd.RootConfig) *Config {
2525
cfg.Flags.BoolVar(&cfg.DryRun, 0, "dry-run", "Show what would be done without actually doing it.")
2626
cfg.Command = &ff.Command{
2727
Name: "upgrade",
28-
Usage: "bine upgrade",
29-
ShortHelp: "Upgrade all binaries defined in the configuration file.",
28+
Usage: "bine upgrade [NAME]",
29+
ShortHelp: "Upgrade binaries defined in the configuration file.",
3030
Flags: cfg.Flags,
3131
Exec: cfg.Exec,
3232
}
@@ -35,12 +35,30 @@ func New(parent *rootcmd.RootConfig) *Config {
3535
}
3636

3737
func (cfg *Config) Exec(ctx context.Context, args []string) error {
38+
if len(args) > 1 {
39+
return errors.New("upgrade accepts at most one argument")
40+
}
41+
3842
var upgradeFn func(ctx context.Context) ([]*bine.ListItem, error)
39-
if cfg.DryRun {
43+
name := ""
44+
if len(args) == 1 {
45+
name = args[0]
46+
}
47+
48+
switch {
49+
case cfg.DryRun && name != "":
50+
upgradeFn = func(ctx context.Context) ([]*bine.ListItem, error) {
51+
return dryRunOne(ctx, cfg.Bine, name)
52+
}
53+
case cfg.DryRun:
4054
upgradeFn = func(ctx context.Context) ([]*bine.ListItem, error) {
4155
return cfg.Bine.List(ctx, false, true)
4256
}
43-
} else {
57+
case name != "":
58+
upgradeFn = func(ctx context.Context) ([]*bine.ListItem, error) {
59+
return cfg.Bine.UpgradeOne(ctx, name)
60+
}
61+
default:
4462
upgradeFn = func(ctx context.Context) ([]*bine.ListItem, error) {
4563
return cfg.Bine.Upgrade(ctx)
4664
}
@@ -76,3 +94,7 @@ func (cfg *Config) Exec(ctx context.Context, args []string) error {
7694

7795
return nil
7896
}
97+
98+
func dryRunOne(ctx context.Context, b *bine.Bine, name string) ([]*bine.ListItem, error) {
99+
return b.ListOne(ctx, name, false, true)
100+
}

‎testdata/upgrade.txtar‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ bine upgrade --dry-run
1010
cmp stdout ../upgrade
1111
! stderr .
1212

13+
bine upgrade --dry-run perpignan
14+
cmp stdout ../upgrade
15+
! stderr .
16+
1317
bine upgrade
1418
stdout 'Upgrade process completed'
1519

0 commit comments

Comments
 (0)