feat(cli): architecture picker + post-fetch O/C/Enter menu

When multiple download links are returned (e.g. x32+x64 for consumer
ISOs), an architecture picker is shown before printing the URL.

After the URL is printed, an interactive menu lets the user open the
link in the default browser (O), copy it to the clipboard (C), or exit
(Enter). Menu is suppressed when stdout is not a terminal (piping).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Shekhar Vaidya 2026-06-23 11:49:31 +05:30
parent 29d6b6b3f1
commit 3e45bfd0c7
2 changed files with 115 additions and 6 deletions

View file

@ -308,18 +308,42 @@ func runConsumer(productID, query, langName string, noContribute bool) error {
}
fmt.Fprintln(os.Stderr, "")
for _, link := range links {
var selectedURI string
if isTerminal() && len(links) > 1 {
link, err := pickArchitecture(links)
if err != nil {
return err
}
name := urlFilename(link.URI)
fmt.Fprintf(os.Stderr, " %s\n", name)
fmt.Fprintf(os.Stderr, " %s\n", strings.Repeat("─", len(name)))
fmt.Println(link.URI) // stdout — stays clean for piping
fmt.Fprintln(os.Stderr, "")
fmt.Fprintf(os.Stderr, "\n %s\n", name)
fmt.Fprintf(os.Stderr, " %s\n\n", strings.Repeat("─", len(name)))
fmt.Println(link.URI)
selectedURI = link.URI
} else {
for _, link := range links {
name := urlFilename(link.URI)
fmt.Fprintf(os.Stderr, " %s\n", name)
fmt.Fprintf(os.Stderr, " %s\n", strings.Repeat("─", len(name)))
fmt.Println(link.URI) // stdout — stays clean for piping
fmt.Fprintln(os.Stderr, "")
}
if len(links) == 1 {
selectedURI = links[0].URI
}
}
if !noContribute {
fmt.Fprintln(os.Stderr, " ✓ Shared with MSDL Web App (https://msdl.tech-latest.com/)")
fmt.Fprintln(os.Stderr, " Opt out: --no-contribute")
fmt.Fprintln(os.Stderr, "")
}
if isTerminal() && selectedURI != "" {
postFetchMenu(selectedURI)
}
if !noContribute {
// Wait up to 5s for the contribution to complete before process exit.
done := make(chan struct{})
go func() { wg.Wait(); close(done) }()
@ -359,6 +383,9 @@ func runEval(slug string) error {
if len(links) == 1 {
fmt.Println(links[0].URL)
if isTerminal() {
postFetchMenu(links[0].URL)
}
return nil
}
@ -377,6 +404,10 @@ func runEval(slug string) error {
if err != nil {
return err
}
fmt.Println(links[n-1].URL)
selected := links[n-1].URL
fmt.Println(selected)
if isTerminal() {
postFetchMenu(selected)
}
return nil
}

View file

@ -5,6 +5,8 @@ import (
"fmt"
"io"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
)
@ -76,3 +78,79 @@ func pickEvalProduct(products []EvalProduct) (EvalProduct, error) {
}
return products[n-1], nil
}
func isTerminal() bool {
fi, err := os.Stdin.Stat()
if err != nil {
return false
}
return fi.Mode()&os.ModeCharDevice != 0
}
func pickArchitecture(links []DownloadLink) (DownloadLink, error) {
fmt.Fprintln(os.Stderr, "Select architecture:")
for i, l := range links {
label := l.Architecture
if label == "" {
label = fmt.Sprintf("link %d", i+1)
}
fmt.Fprintf(os.Stderr, " %2d. %s\n", i+1, label)
}
fmt.Fprint(os.Stderr, "\nChoice: ")
n, err := parseChoice(os.Stdin, len(links))
if err != nil {
return DownloadLink{}, err
}
return links[n-1], nil
}
func openInBrowser(rawURL string) error {
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("cmd", "/c", "start", "", rawURL)
case "darwin":
cmd = exec.Command("open", rawURL)
default:
cmd = exec.Command("xdg-open", rawURL)
}
return cmd.Run()
}
func copyToClipboard(text string) error {
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("cmd", "/c", "clip")
case "darwin":
cmd = exec.Command("pbcopy")
default:
if _, err := exec.LookPath("xclip"); err == nil {
cmd = exec.Command("xclip", "-selection", "clipboard")
} else {
cmd = exec.Command("xsel", "--clipboard", "--input")
}
}
cmd.Stdin = strings.NewReader(text)
return cmd.Run()
}
func postFetchMenu(uri string) {
fmt.Fprint(os.Stderr, "\n [O] Open in browser [C] Copy to clipboard [Enter] Exit\n > ")
scanner := bufio.NewScanner(os.Stdin)
if !scanner.Scan() {
return
}
switch strings.ToLower(strings.TrimSpace(scanner.Text())) {
case "o":
if err := openInBrowser(uri); err != nil {
fmt.Fprintln(os.Stderr, " Could not open browser:", err)
}
case "c":
if err := copyToClipboard(uri); err != nil {
fmt.Fprintln(os.Stderr, " Could not copy to clipboard:", err)
} else {
fmt.Fprintln(os.Stderr, " ✓ Copied to clipboard")
}
}
}