Skip to content

Commit 267a09e

Browse files
fix: ask interactive auto-pause in create
1 parent 052602a commit 267a09e

2 files changed

Lines changed: 77 additions & 27 deletions

File tree

cmd/sandbox/create.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,24 @@ func runCreate(c *cli.Context) error {
109109
// Lets users walk through name / rootfs / network / ssh keys without
110110
// remembering every flag. Headless callers continue to get the
111111
// "use --shape" error.
112+
// Pre-parse --auto-pause so the wizard can skip the step when supplied.
113+
var autoPauseSecs *int
114+
if raw := strings.TrimSpace(c.String("auto-pause")); raw != "" {
115+
secs, parseErr := parseDurationToSeconds(raw)
116+
if parseErr != nil {
117+
return fmt.Errorf("--auto-pause %q: %w", raw, parseErr)
118+
}
119+
autoPauseSecs = &secs
120+
}
121+
112122
if shape == "" {
113123
w, werr := runCreateWizard(c, client, wizardSeed{
114-
name: name,
115-
rootfs: rootfs,
116-
ingress: ingress,
117-
netIDs: netIDs,
118-
sshKeys: sshKeys,
124+
name: name,
125+
rootfs: rootfs,
126+
ingress: ingress,
127+
netIDs: netIDs,
128+
sshKeys: sshKeys,
129+
autoPauseSecs: autoPauseSecs,
119130
})
120131
if werr != nil {
121132
return werr
@@ -138,6 +149,9 @@ func runCreate(c *cli.Context) error {
138149
sshKeys = w.sshKeys
139150
}
140151
ingress = ingress || w.ingress
152+
if autoPauseSecs == nil {
153+
autoPauseSecs = w.autoPauseSecs
154+
}
141155
}
142156

143157
req := api.SandboxCreateReq{
@@ -177,12 +191,8 @@ func runCreate(c *cli.Context) error {
177191
req.Disks = disks
178192
}
179193

180-
if raw := strings.TrimSpace(c.String("auto-pause")); raw != "" {
181-
secs, parseErr := parseDurationToSeconds(raw)
182-
if parseErr != nil {
183-
return fmt.Errorf("--auto-pause %q: %w", raw, parseErr)
184-
}
185-
req.AutoPauseAfterSeconds = &secs
194+
if autoPauseSecs != nil {
195+
req.AutoPauseAfterSeconds = autoPauseSecs
186196
}
187197

188198
spinner, _ := pterm.DefaultSpinner.Start("Creating sandbox…") //nolint:errcheck

cmd/sandbox/wizard.go

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,24 @@ import (
1717
// wizardSeed lets the caller pre-fill some answers so already-supplied
1818
// flags aren't asked for again.
1919
type wizardSeed struct {
20-
name string
21-
rootfs string
22-
ingress bool
23-
netIDs []string
24-
sshKeys []string // canonicalised key strings (NOT paths)
20+
name string
21+
rootfs string
22+
ingress bool
23+
netIDs []string
24+
sshKeys []string // canonicalised key strings (NOT paths)
25+
autoPauseSecs *int // nil = not supplied via flag
2526
}
2627

2728
// wizardResult is what runCreateWizard returns when the user finished.
2829
// nil result = user cancelled (caller exits quietly).
2930
type wizardResult struct {
30-
shape string
31-
name string
32-
rootfs string
33-
ingress bool
34-
netIDs []string
35-
sshKeys []string // canonicalised key strings (NOT paths)
31+
shape string
32+
name string
33+
rootfs string
34+
ingress bool
35+
netIDs []string
36+
sshKeys []string // canonicalised key strings (NOT paths)
37+
autoPauseSecs *int // nil = disabled
3638
}
3739

3840
// runCreateWizard walks the user through shape → name → rootfs → ingress
@@ -50,11 +52,12 @@ func runCreateWizard(c *cli.Context, client *api.SandboxClient, seed wizardSeed)
5052
return nil, fmt.Errorf("please choose a size with --shape\n\n To see the options, run:\n createos sandbox shapes")
5153
}
5254
out := &wizardResult{
53-
name: seed.name,
54-
rootfs: seed.rootfs,
55-
ingress: seed.ingress,
56-
netIDs: append([]string{}, seed.netIDs...),
57-
sshKeys: append([]string{}, seed.sshKeys...),
55+
name: seed.name,
56+
rootfs: seed.rootfs,
57+
ingress: seed.ingress,
58+
netIDs: append([]string{}, seed.netIDs...),
59+
sshKeys: append([]string{}, seed.sshKeys...),
60+
autoPauseSecs: seed.autoPauseSecs,
5861
}
5962

6063
// ── 1. Shape (required) ─────────────────────────────────────────
@@ -125,6 +128,16 @@ func runCreateWizard(c *cli.Context, client *api.SandboxClient, seed wizardSeed)
125128
}
126129
}
127130

131+
// ── 7. Auto-pause (optional; skip if already supplied via --auto-pause) ──
132+
if out.autoPauseSecs == nil {
133+
secs, err := wizardPickAutoPause()
134+
if err != nil {
135+
pterm.Println(pterm.Gray(fmt.Sprintf(" Auto-pause step skipped (%v).", err)))
136+
} else {
137+
out.autoPauseSecs = secs
138+
}
139+
}
140+
128141
return out, nil
129142
}
130143

@@ -339,6 +352,33 @@ func relToHome(path, home string) string {
339352
return path
340353
}
341354

355+
// wizardPickAutoPause asks whether the sandbox should pause itself when idle.
356+
// Returns nil (no auto-pause) if the user skips or types nothing.
357+
func wizardPickAutoPause() (*int, error) {
358+
pterm.Println()
359+
pterm.NewStyle(pterm.FgCyan).Println(" Auto-pause")
360+
pterm.Println(pterm.Gray(" Your sandbox can pause itself automatically when you're not using it,"))
361+
pterm.Println(pterm.Gray(" saving resources. It resumes instantly the next time you need it."))
362+
pterm.Println(pterm.Gray(" Leave blank to keep it running until you stop it manually."))
363+
364+
input, err := pterm.DefaultInteractiveTextInput.
365+
WithDefaultText("Pause after how long with no activity? (e.g. 10m, 1h — leave blank to skip)").
366+
Show()
367+
if err != nil {
368+
return nil, err
369+
}
370+
input = strings.TrimSpace(input)
371+
if input == "" {
372+
return nil, nil
373+
}
374+
secs, err := parseDurationToSeconds(input)
375+
if err != nil {
376+
pterm.Println(pterm.Gray(fmt.Sprintf(" Didn't recognise %q — skipping auto-pause.", input)))
377+
return nil, nil
378+
}
379+
return &secs, nil
380+
}
381+
342382
// stringSliceCleanup trims and drops empty entries — pulled out of
343383
// runCreate so the wizard plumbing can reuse it.
344384
func stringSliceCleanup(raw []string) []string {

0 commit comments

Comments
 (0)