chore: clean up sipp cli args 0a33acfa
Steve · 2026-05-17 19:09 5 file(s) · +124 −117
apps/sipp-go/cmd_auth.go (added) +48 −0
1 +
package main
2 +
3 +
import (
4 +
	"bufio"
5 +
	"fmt"
6 +
	"os"
7 +
	"strings"
8 +
	"syscall"
9 +
10 +
	"github.com/stevedylandev/andromeda/apps/sipp-go/tui"
11 +
	"golang.org/x/term"
12 +
)
13 +
14 +
func runAuth(_ []string) {
15 +
	cfg, _ := tui.LoadConfig()
16 +
	reader := bufio.NewReader(os.Stdin)
17 +
18 +
	defaultURL := cfg.RemoteURL
19 +
	if defaultURL == "" {
20 +
		defaultURL = "http://localhost:3000"
21 +
	}
22 +
	fmt.Printf("Remote URL [%s]: ", defaultURL)
23 +
	line, _ := reader.ReadString('\n')
24 +
	line = strings.TrimSpace(line)
25 +
	if line != "" {
26 +
		cfg.RemoteURL = line
27 +
	} else {
28 +
		cfg.RemoteURL = defaultURL
29 +
	}
30 +
31 +
	fmt.Print("API key (hidden): ")
32 +
	keyBytes, err := term.ReadPassword(int(syscall.Stdin))
33 +
	fmt.Println()
34 +
	if err != nil {
35 +
		fmt.Fprintln(os.Stderr, "read api key:", err)
36 +
		os.Exit(1)
37 +
	}
38 +
	if k := strings.TrimSpace(string(keyBytes)); k != "" {
39 +
		cfg.APIKey = k
40 +
	}
41 +
42 +
	if err := tui.SaveConfig(cfg); err != nil {
43 +
		fmt.Fprintln(os.Stderr, "save config:", err)
44 +
		os.Exit(1)
45 +
	}
46 +
	path, _ := tui.ConfigPath()
47 +
	fmt.Println("Saved", path)
48 +
}
apps/sipp-go/cmd_upload.go (added) +69 −0
1 +
package main
2 +
3 +
import (
4 +
	"fmt"
5 +
	"os"
6 +
	"path/filepath"
7 +
	"strings"
8 +
9 +
	"github.com/atotto/clipboard"
10 +
	"github.com/stevedylandev/andromeda/apps/sipp-go/tui"
11 +
)
12 +
13 +
func runUpload(args []string) {
14 +
	var file string
15 +
	for _, a := range args {
16 +
		if !strings.HasPrefix(a, "-") {
17 +
			file = a
18 +
			break
19 +
		}
20 +
	}
21 +
	if file == "" {
22 +
		fmt.Fprintln(os.Stderr, "no file specified")
23 +
		fmt.Fprint(os.Stderr, usage)
24 +
		os.Exit(2)
25 +
	}
26 +
27 +
	data, err := os.ReadFile(file)
28 +
	if err != nil {
29 +
		fmt.Fprintln(os.Stderr, "read file:", err)
30 +
		os.Exit(1)
31 +
	}
32 +
	name := filepath.Base(file)
33 +
34 +
	opts := tui.ParseArgs(args)
35 +
	if opts.RemoteURL == "" {
36 +
		opts.RemoteURL = os.Getenv("SIPP_REMOTE_URL")
37 +
	}
38 +
	if opts.RemoteURL == "" {
39 +
		cfg, _ := tui.LoadConfig()
40 +
		opts.RemoteURL = cfg.RemoteURL
41 +
	}
42 +
	if opts.RemoteURL == "" {
43 +
		fmt.Fprintln(os.Stderr, "remote URL not set (use -r, SIPP_REMOTE_URL, or `sipp auth`)")
44 +
		os.Exit(2)
45 +
	}
46 +
47 +
	backend, err := tui.ResolveBackend(opts)
48 +
	if err != nil {
49 +
		fmt.Fprintln(os.Stderr, "backend:", err)
50 +
		os.Exit(1)
51 +
	}
52 +
	defer backend.Close()
53 +
54 +
	snippet, err := backend.Create(name, string(data))
55 +
	if err != nil {
56 +
		fmt.Fprintln(os.Stderr, "create snippet:", err)
57 +
		os.Exit(1)
58 +
	}
59 +
60 +
	if remote := backend.RemoteURL(); remote != "" {
61 +
		link := strings.TrimRight(remote, "/") + "/s/" + snippet.ShortID
62 +
		fmt.Println(link)
63 +
		if err := clipboard.WriteAll(link); err == nil {
64 +
			fmt.Println("(copied to clipboard)")
65 +
		}
66 +
	} else {
67 +
		fmt.Println("created:", snippet.ShortID)
68 +
	}
69 +
}
apps/sipp-go/go.mod +2 −1
41 41
	golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
42 42
	golang.org/x/mod v0.25.0 // indirect
43 43
	golang.org/x/sync v0.20.0 // indirect
44 -
	golang.org/x/sys v0.43.0 // indirect
44 +
	golang.org/x/sys v0.44.0 // indirect
45 +
	golang.org/x/term v0.43.0 // indirect
45 46
	modernc.org/libc v1.65.7 // indirect
46 47
	modernc.org/mathutil v1.7.1 // indirect
47 48
	modernc.org/memory v1.11.0 // indirect
apps/sipp-go/go.sum +4 −0
77 77
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
78 78
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
79 79
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
80 +
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
81 +
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
82 +
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
83 +
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
80 84
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
81 85
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
82 86
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
apps/sipp-go/main.go +1 −116
9 9
package main
10 10
11 11
import (
12 -
	"bufio"
13 -
	"bytes"
14 -
	"encoding/json"
15 12
	"fmt"
16 -
	"io"
17 -
	"net/http"
18 13
	"os"
19 -
	"path/filepath"
20 14
	"strconv"
21 -
	"strings"
22 15
23 16
	"github.com/stevedylandev/andromeda/apps/sipp-go/server"
24 17
	"github.com/stevedylandev/andromeda/apps/sipp-go/tui"
55 48
	case "tui":
56 49
		runTUI(args[1:])
57 50
	case "auth":
58 -
		runAuth()
51 +
		runAuth(args[1:])
59 52
	default:
60 53
		runUpload(args)
61 54
	}
93 86
		os.Exit(1)
94 87
	}
95 88
}
96 -
97 -
func runAuth() {
98 -
	cfg, _ := tui.LoadConfig()
99 -
	in := bufio.NewReader(os.Stdin)
100 -
101 -
	fmt.Printf("Remote URL [%s]: ", cfg.RemoteURL)
102 -
	url, _ := in.ReadString('\n')
103 -
	url = strings.TrimSpace(url)
104 -
	if url != "" {
105 -
		cfg.RemoteURL = url
106 -
	}
107 -
108 -
	masked := ""
109 -
	if cfg.APIKey != "" {
110 -
		masked = "********"
111 -
	}
112 -
	fmt.Printf("API key [%s]: ", masked)
113 -
	key, _ := in.ReadString('\n')
114 -
	key = strings.TrimSpace(key)
115 -
	if key != "" {
116 -
		cfg.APIKey = key
117 -
	}
118 -
119 -
	if err := tui.SaveConfig(cfg); err != nil {
120 -
		fmt.Fprintln(os.Stderr, "save config:", err)
121 -
		os.Exit(1)
122 -
	}
123 -
	path, _ := tui.ConfigPath()
124 -
	fmt.Println("saved", path)
125 -
}
126 -
127 -
func runUpload(args []string) {
128 -
	remote := os.Getenv("SIPP_REMOTE_URL")
129 -
	apiKey := os.Getenv("SIPP_API_KEY")
130 -
	var file string
131 -
	for i := 0; i < len(args); i++ {
132 -
		switch args[i] {
133 -
		case "-r", "--remote":
134 -
			if i+1 < len(args) {
135 -
				remote = args[i+1]
136 -
				i++
137 -
			}
138 -
		case "-k", "--api-key":
139 -
			if i+1 < len(args) {
140 -
				apiKey = args[i+1]
141 -
				i++
142 -
			}
143 -
		default:
144 -
			if !strings.HasPrefix(args[i], "-") {
145 -
				file = args[i]
146 -
			}
147 -
		}
148 -
	}
149 -
	if file == "" {
150 -
		fmt.Fprintln(os.Stderr, "no file specified")
151 -
		fmt.Fprint(os.Stderr, usage)
152 -
		os.Exit(2)
153 -
	}
154 -
	if remote == "" {
155 -
		cfg, _ := tui.LoadConfig()
156 -
		if cfg.RemoteURL != "" {
157 -
			remote = cfg.RemoteURL
158 -
		}
159 -
		if apiKey == "" {
160 -
			apiKey = cfg.APIKey
161 -
		}
162 -
	}
163 -
	if remote == "" {
164 -
		fmt.Fprintln(os.Stderr, "remote URL not set (use -r, SIPP_REMOTE_URL, or `sipp auth`)")
165 -
		os.Exit(2)
166 -
	}
167 -
168 -
	data, err := os.ReadFile(file)
169 -
	if err != nil {
170 -
		fmt.Fprintln(os.Stderr, err)
171 -
		os.Exit(1)
172 -
	}
173 -
	body, _ := json.Marshal(map[string]string{
174 -
		"name":    filepath.Base(file),
175 -
		"content": string(data),
176 -
	})
177 -
	req, err := http.NewRequest(http.MethodPost, strings.TrimRight(remote, "/")+"/api/snippets", bytes.NewReader(body))
178 -
	if err != nil {
179 -
		fmt.Fprintln(os.Stderr, err)
180 -
		os.Exit(1)
181 -
	}
182 -
	req.Header.Set("Content-Type", "application/json")
183 -
	if apiKey != "" {
184 -
		req.Header.Set("x-api-key", apiKey)
185 -
	}
186 -
	resp, err := http.DefaultClient.Do(req)
187 -
	if err != nil {
188 -
		fmt.Fprintln(os.Stderr, err)
189 -
		os.Exit(1)
190 -
	}
191 -
	defer resp.Body.Close()
192 -
	respBody, _ := io.ReadAll(resp.Body)
193 -
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
194 -
		fmt.Fprintf(os.Stderr, "server returned %s: %s\n", resp.Status, string(respBody))
195 -
		os.Exit(1)
196 -
	}
197 -
	var s server.Snippet
198 -
	if err := json.Unmarshal(respBody, &s); err != nil {
199 -
		fmt.Fprintln(os.Stderr, "could not parse response:", err)
200 -
		os.Exit(1)
201 -
	}
202 -
	fmt.Println(strings.TrimRight(remote, "/") + "/s/" + s.ShortID)
203 -
}