Skip to content

Commit 2ea5f3c

Browse files
authored
fix: audit and fix all CLI commands (#5)
1 parent 5010d02 commit 2ea5f3c

1 file changed

Lines changed: 83 additions & 22 deletions

File tree

cmd/clipx/main.go

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ func main() {
6666
case "help", "--help", "-h":
6767
printUsage()
6868
return
69+
default:
70+
fmt.Fprintf(os.Stderr, "unknown command: %s\nrun 'clipx help' for usage\n", os.Args[1])
71+
os.Exit(1)
6972
}
7073
}
7174

@@ -156,7 +159,7 @@ func cmdPair(addr string) {
156159
}
157160

158161
fmt.Printf("✓ paired with %s\n", resolved)
159-
fmt.Println(" restart clipx or run 'clipx install' to apply")
162+
restartIfRunning()
160163
}
161164

162165
func cmdUnpair(addr string) {
@@ -193,6 +196,7 @@ func cmdUnpair(addr string) {
193196
}
194197

195198
fmt.Printf("✓ unpaired from %s\n", addr)
199+
restartIfRunning()
196200
}
197201

198202
func cmdPeers() {
@@ -213,7 +217,7 @@ func cmdPeers() {
213217
func cmdStatus() {
214218
out, err := exec.Command("launchctl", "list", launchAgentLabel).Output()
215219
if err != nil {
216-
fmt.Println(" clipx is not running as a LaunchAgent")
220+
fmt.Println(" clipx is not running as a LaunchAgent")
217221
} else {
218222
fmt.Println("● clipx is running as a LaunchAgent")
219223
fmt.Println(string(out))
@@ -237,33 +241,86 @@ func cmdStatus() {
237241
}
238242
}
239243

244+
// detectInstallMethod returns "brew", "go", or "binary" based on
245+
// where the current clipx binary lives.
246+
func detectInstallMethod() string {
247+
exePath, err := os.Executable()
248+
if err != nil {
249+
return "binary"
250+
}
251+
exePath, _ = filepath.EvalSymlinks(exePath)
252+
253+
if strings.Contains(exePath, "Cellar") || strings.Contains(exePath, "homebrew") {
254+
return "brew"
255+
}
256+
257+
gopath := os.Getenv("GOPATH")
258+
if gopath == "" {
259+
home, _ := os.UserHomeDir()
260+
gopath = filepath.Join(home, "go")
261+
}
262+
if strings.HasPrefix(exePath, filepath.Join(gopath, "bin")) {
263+
return "go"
264+
}
265+
266+
return "binary"
267+
}
268+
240269
func cmdUpdate() {
241270
current := getVersion()
242271
fmt.Printf("current version: %s\n", current)
243-
fmt.Println("updating via go install...")
244-
245-
cmd := exec.Command("go", "install", "github.com/gomantics/clipx/cmd/clipx@latest")
246-
cmd.Env = append(os.Environ(),
247-
"GONOSUMDB=github.com/gomantics/clipx",
248-
"GONOSUMCHECK=github.com/gomantics/clipx",
249-
)
250-
cmd.Stdout = os.Stdout
251-
cmd.Stderr = os.Stderr
252-
if err := cmd.Run(); err != nil {
253-
fmt.Fprintf(os.Stderr, "error: go install failed: %v\n", err)
272+
273+
method := detectInstallMethod()
274+
275+
switch method {
276+
case "brew":
277+
fmt.Println("installed via Homebrew, updating...")
278+
cmd := exec.Command("brew", "upgrade", "clipx")
279+
cmd.Stdout = os.Stdout
280+
cmd.Stderr = os.Stderr
281+
if err := cmd.Run(); err != nil {
282+
fmt.Fprintf(os.Stderr, "error: brew upgrade failed: %v\n", err)
283+
os.Exit(1)
284+
}
285+
286+
case "go":
287+
fmt.Println("installed via go install, updating...")
288+
cmd := exec.Command("go", "install", "github.com/gomantics/clipx/cmd/clipx@latest")
289+
cmd.Env = append(os.Environ(),
290+
"GONOSUMDB=github.com/gomantics/clipx",
291+
"GONOSUMCHECK=github.com/gomantics/clipx",
292+
)
293+
cmd.Stdout = os.Stdout
294+
cmd.Stderr = os.Stderr
295+
if err := cmd.Run(); err != nil {
296+
fmt.Fprintf(os.Stderr, "error: go install failed: %v\n", err)
297+
os.Exit(1)
298+
}
299+
300+
default:
301+
fmt.Fprintln(os.Stderr, "cannot detect install method")
302+
fmt.Fprintln(os.Stderr, "update manually from https://github.com/gomantics/clipx/releases")
254303
os.Exit(1)
255304
}
256305

257306
fmt.Println("✓ clipx updated")
307+
restartIfRunning()
308+
}
258309

310+
// restartIfRunning restarts the LaunchAgent if it's currently loaded.
311+
func restartIfRunning() {
259312
plistPath := launchAgentPath()
260-
if _, err := os.Stat(plistPath); err == nil {
261-
fmt.Println("restarting LaunchAgent...")
262-
exec.Command("launchctl", "unload", plistPath).Run()
263-
time.Sleep(500 * time.Millisecond)
264-
exec.Command("launchctl", "load", plistPath).Run()
265-
fmt.Println("✓ LaunchAgent restarted")
313+
if _, err := os.Stat(plistPath); err != nil {
314+
return // not installed as LaunchAgent
315+
}
316+
if err := exec.Command("launchctl", "list", launchAgentLabel).Run(); err != nil {
317+
return // not currently running
266318
}
319+
fmt.Println("restarting LaunchAgent...")
320+
exec.Command("launchctl", "unload", plistPath).Run()
321+
time.Sleep(500 * time.Millisecond)
322+
exec.Command("launchctl", "load", plistPath).Run()
323+
fmt.Println("✓ LaunchAgent restarted")
267324
}
268325

269326
// --- LaunchAgent ---
@@ -316,9 +373,13 @@ func cmdInstall() {
316373
fmt.Println("adding firewall exception (may require sudo password)...")
317374
fwTool := "/usr/libexec/ApplicationFirewall/socketfilterfw"
318375
if _, err := os.Stat(fwTool); err == nil {
319-
exec.Command("sudo", fwTool, "--add", binPath).Run()
320-
exec.Command("sudo", fwTool, "--unblockapp", binPath).Run()
321-
fmt.Println("✓ firewall exception added")
376+
err1 := exec.Command("sudo", fwTool, "--add", binPath).Run()
377+
err2 := exec.Command("sudo", fwTool, "--unblockapp", binPath).Run()
378+
if err1 != nil || err2 != nil {
379+
fmt.Println("⚠ firewall exception failed — you may need to allow clipx manually")
380+
} else {
381+
fmt.Println("✓ firewall exception added")
382+
}
322383
}
323384

324385
plistPath := launchAgentPath()

0 commit comments

Comments
 (0)