package cmd import ( "fmt" "os/exec" "path" "strings" ) // sshRun executes a shell command on the remote host, returning combined output. // Uses the system ssh binary so existing keys and ~/.ssh/config are honored. func sshRun(user, host, command string) (string, error) { c := exec.Command("ssh", "-o", "BatchMode=yes", user+"@"+host, command) out, err := c.CombinedOutput() if err != nil { trimmed := strings.TrimSpace(string(out)) if trimmed != "" { return string(out), fmt.Errorf("ssh %s@%s: %s: %w", user, host, trimmed, err) } return string(out), fmt.Errorf("ssh %s@%s: command failed: %w", user, host, err) } return string(out), nil } // sshWriteFile writes content to a remote file, creating parent directories. // Content is streamed via stdin to avoid shell escaping issues. func sshWriteFile(user, host, remotePath, content string) error { dir := path.Dir(remotePath) cmd := fmt.Sprintf("mkdir -p %s && cat > %s", dir, remotePath) c := exec.Command("ssh", "-o", "BatchMode=yes", user+"@"+host, cmd) c.Stdin = strings.NewReader(content) if out, err := c.CombinedOutput(); err != nil { return fmt.Errorf("writing %s on %s@%s: %s: %w", remotePath, user, host, strings.TrimSpace(string(out)), err) } return nil }