sshm/cmd/root.go

151 lines
3.6 KiB
Go

package cmd
import (
"fmt"
"log"
"os"
"strings"
"sshm/internal/config"
"sshm/internal/ui"
"github.com/spf13/cobra"
)
// version will be set at build time via -ldflags
var version = "dev"
// configFile holds the path to the SSH config file
var configFile string
var rootCmd = &cobra.Command{
Use: "sshm",
Short: "SSH Manager - A modern SSH connection manager",
Long: `SSHM is a modern SSH manager for your terminal.
Main usage:
Running 'sshm' (without arguments) opens the interactive TUI window to browse, search, and connect to your SSH hosts graphically.
You can also use sshm in CLI mode for direct operations.
Hosts are read from your ~/.ssh/config file by default.`,
Version: version,
Run: func(cmd *cobra.Command, args []string) {
// If no arguments provided, run interactive mode
if len(args) == 0 {
runInteractiveMode()
return
}
// If a host name is provided, connect directly
hostName := args[0]
connectToHost(hostName)
},
}
func runInteractiveMode() {
// Parse SSH configurations
var hosts []config.SSHHost
var err error
if configFile != "" {
hosts, err = config.ParseSSHConfigFile(configFile)
} else {
hosts, err = config.ParseSSHConfig()
}
if err != nil {
log.Fatalf("Error reading SSH config file: %v", err)
}
if len(hosts) == 0 {
fmt.Println("No SSH hosts found in your ~/.ssh/config file.")
fmt.Print("Would you like to add a new host now? [y/N]: ")
var response string
_, err := fmt.Scanln(&response)
if err == nil && (response == "y" || response == "Y") {
err := ui.RunAddForm("", configFile)
if err != nil {
fmt.Printf("Error adding host: %v\n", err)
}
// After adding, try to reload hosts and continue if any exist
if configFile != "" {
hosts, err = config.ParseSSHConfigFile(configFile)
} else {
hosts, err = config.ParseSSHConfig()
}
if err != nil || len(hosts) == 0 {
fmt.Println("No hosts available, exiting.")
os.Exit(1)
}
} else {
fmt.Println("No hosts available, exiting.")
os.Exit(1)
}
}
// Run the interactive TUI
if err := ui.RunInteractiveMode(hosts, configFile); err != nil {
log.Fatalf("Error running interactive mode: %v", err)
}
}
func connectToHost(hostName string) {
// Parse SSH configurations to verify host exists
var hosts []config.SSHHost
var err error
if configFile != "" {
hosts, err = config.ParseSSHConfigFile(configFile)
} else {
hosts, err = config.ParseSSHConfig()
}
if err != nil {
log.Fatalf("Error reading SSH config file: %v", err)
}
// Check if host exists
var hostFound bool
for _, host := range hosts {
if host.Name == hostName {
hostFound = true
break
}
}
if !hostFound {
fmt.Printf("Error: Host '%s' not found in SSH configuration.\n", hostName)
fmt.Println("Use 'sshm' to see available hosts.")
os.Exit(1)
}
// Connect to the host
fmt.Printf("Connecting to %s...\n", hostName)
// Build the SSH command with the appropriate config file
var sshCmd []string
if configFile != "" {
sshCmd = []string{"ssh", "-F", configFile, hostName}
} else {
sshCmd = []string{"ssh", hostName}
}
// Note: In a real implementation, you'd use exec.Command here
// For now, just print the command that would be executed
fmt.Printf("%s\n", strings.Join(sshCmd, " "))
}
// Execute adds all child commands to the root command and sets flags appropriately.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
func init() {
// Add the config file flag
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "SSH config file to use (default: ~/.ssh/config)")
}