Files
HostKeeper/v1/cmd/hostkeeper/root.go
T
swanadiva 847989df75 refactor: move V1 code into v1/ subdirectory
- git mv cmd/ internal/ pkg/ test/ go.mod go.sum Makefile build.sh docs/ v1/
- Create v1/README.md with V1 documentation
- Update root README for V1 + V2 structure
- V1 still builds (cd v1 && go build ./cmd/hostkeeper) and 105 tests pass
- Root is now clean for V2 development
2026-07-07 11:56:27 +07:00

102 lines
2.6 KiB
Go

package main
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"git.tukangketik.id/swanadiva/hostkeeper/pkg/config"
"git.tukangketik.id/swanadiva/hostkeeper/pkg/storage"
)
var (
cfgFile string
appCfg *config.Config
verbose int
debug bool
passwordFlag string
)
var rootCmd = &cobra.Command{
Use: "hostkeeper",
Short: "Cross-platform SSH/SFTP management tool",
Long: `Hostkeeper - Cross-platform SSH/SFTP Management Tool
A comprehensive SSH/SFTP management tool with secure credential storage,
host management, and cross-device sync capabilities.
Quick Start:
hostkeeper add myserver --host 192.168.1.10 --user admin
hostkeeper list
hostkeeper connect myserver
For more information, visit the project repository.`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// Initialize configuration
cfg, err := config.New()
if err != nil {
return fmt.Errorf("failed to initialize config: %w", err)
}
appCfg = cfg
return nil
},
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is platform-specific app dir)")
rootCmd.PersistentFlags().CountVarP(&verbose, "verbose", "v", "verbose output (-v for info, -vv for debug)")
rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "enable debug mode")
rootCmd.PersistentFlags().StringVar(&passwordFlag, "password", "", "master password for encrypted storage")
rootCmd.AddCommand(versionCmd)
}
// initConfig reads in config file and ENV variables if set
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
// Use platform-specific config directory
cfg, err := config.New()
if err != nil {
return
}
viper.AddConfigPath(cfg.GetConfigDir())
viper.SetConfigType("json")
viper.SetConfigName("config")
}
viper.AutomaticEnv()
// Read config file (ignore if not found for first run)
_ = viper.ReadInConfig()
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number",
Long: `Print the version and build information for HostKeeper.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("hostkeeper %s (built: %s)\n", version, buildTime)
},
}
// Execute runs the root command
func Execute() error {
return rootCmd.Execute()
}
// newStorage creates a new JSONStorage with the password flag applied
func newStorage(cfg *config.Config) (*storage.JSONStorage, error) {
store, err := storage.NewJSONStorage(cfg.GetDataDir())
if err != nil {
return nil, err
}
if passwordFlag != "" {
store.SetPassword(passwordFlag)
}
return store, nil
}