diff --git a/cmd/relay/config.go b/cmd/relay/config.go index 2e8a2d2..8e3c262 100644 --- a/cmd/relay/config.go +++ b/cmd/relay/config.go @@ -18,7 +18,7 @@ type RelayConfig struct { func initConfig(defaultProfileName string) RelayConfig { config.SetDefaultProfileName(defaultProfileName) - config.ParseCommonFlags(true) + config.CommonFlagsetParse(true) config.Init() c := RelayConfig{ diff --git a/config/actor.go b/config/actor.go index bf50a61..803fc12 100644 --- a/config/actor.go +++ b/config/actor.go @@ -24,47 +24,37 @@ const ( ) var ( - ActorFlags = *pflag.NewFlagSet("actor", pflag.ContinueOnError) + actorFlagset = pflag.NewFlagSet("actor", pflag.ExitOnError) actorKeyset set.Keyset - actorOnce sync.Once + actorFlagsOnce sync.Once ErrEmptyIdentity = fmt.Errorf("identity is empty") ErrEmptyNick = fmt.Errorf("nick is empty") ErrFakeIdentity = fmt.Errorf("your identity is fake. You need to define actorKeyset or generate a new one") + nick string + location string ) // Initialise command line flags for the actor package // The actor is optional for some commands, but required for others. // exitOnHelp means that this function is the last called when help is needed. // and the program should exit. -func ParseActorFlags(exitOnHelp bool) { +func actorFlags() { - InitCommon() - InitLog() - InitDB() - InitP2P() - InitHTTP() + actorFlagsOnce.Do(func() { - actorOnce.Do(func() { + actorFlagset.StringVarP(&nick, "nick", "n", "", "Nickname to use in character creation") + actorFlagset.StringVarP(&location, "location", "l", defaultLocation, "DID of the location to visit") - ActorFlags.StringP("nick", "n", "", "Nickname to use in character creation") - ActorFlags.StringP("location", "l", defaultLocation, "DID of the location to visit") - - viper.BindPFlag("actor.nick", ActorFlags.Lookup("nick")) - viper.BindPFlag("actor.location", ActorFlags.Lookup("location")) + viper.BindPFlag("actor.nick", actorFlagset.Lookup("nick")) + viper.BindPFlag("actor.location", actorFlagset.Lookup("location")) viper.SetDefault("actor.location", defaultLocation) viper.SetDefault("actor.nick", defaultNick()) if HelpNeeded() { fmt.Println("Actor Flags:") - ActorFlags.PrintDefaults() - - if exitOnHelp { - os.Exit(0) - } + actorFlagset.PrintDefaults() - } else { - ActorFlags.Parse(os.Args[1:]) } }) } @@ -105,6 +95,11 @@ func Actor() ActorConfig { // needs to fetch the nick from the command line if it's not in the config. // Due to being a required parameter when generating a new keyset. func ActorNick() string { + + // This is used early, so command line takes precedence + if actorFlagset.Lookup("nick").Changed { + return actorFlagset.Lookup("nick").Value.String() + } return viper.GetString("actor.nick") } diff --git a/config/common.go b/config/common.go index def2b73..dc8ca06 100644 --- a/config/common.go +++ b/config/common.go @@ -2,16 +2,15 @@ package config import ( "fmt" - "os" "sync" "github.com/spf13/pflag" ) var ( - CommonFlags = pflag.NewFlagSet("common", pflag.ContinueOnError) + commonFlagset = pflag.NewFlagSet("common", pflag.ExitOnError) - commonOnce sync.Once + commonFlagsOnce sync.Once debugFlag bool = false forceFlag bool = false @@ -21,29 +20,28 @@ var ( versionCommandFlag bool = false ) -func InitCommon() { +func InitCommonFlagset() { - commonOnce.Do(func() { + commonFlagsOnce.Do(func() { // Allow to set config file via command line flag. - CommonFlags.StringP("config", "c", "", "Config file to use.") - CommonFlags.StringP("profile", "p", "", "Config profile (name) to use.") + commonFlagset.StringP("config", "c", "", "Config file to use.") + commonFlagset.StringP("profile", "p", "", "Config profile (name) to use.") - // COmmands - CommonFlags.BoolVar(&showConfigCommandFlag, "show-config", false, "Whether to print the config.") - CommonFlags.BoolVarP(&versionCommandFlag, "version", "v", false, "Print version and exit.") - CommonFlags.BoolVar(&generateCommandFlag, "generate", false, "Generates a new keyset") + // Commands + commonFlagset.BoolVar(&showConfigCommandFlag, "show-config", false, "Whether to print the config.") + commonFlagset.BoolVarP(&versionCommandFlag, "version", "v", false, "Print version and exit.") + commonFlagset.BoolVar(&generateCommandFlag, "generate", false, "Generates a new keyset") // Flags - CommonFlags.BoolVar(&forceFlag, "force", false, "Forces regneration of config keyset and publishing") - CommonFlags.BoolVar(&debugFlag, "debug", false, "Port to listen on for debug endpoints") + commonFlagset.BoolVar(&forceFlag, "force", false, "Forces regneration of config keyset and publishing") + commonFlagset.BoolVar(&debugFlag, "debug", false, "Port to listen on for debug endpoints") if HelpNeeded() { - fmt.Println("Common flags:") - CommonFlags.PrintDefaults() - } else { - CommonFlags.Parse(os.Args[1:]) + fmt.Println("Common Flags:") + commonFlagset.PrintDefaults() } + }) } @@ -58,19 +56,6 @@ after help is printed. This is useful for the main function, when this is the last flag parsing function called. */ -func ParseCommonFlags(exitOnHelp bool) { - - InitCommon() - InitLog() - InitDB() - InitP2P() - InitHTTP() - - if HelpNeeded() && exitOnHelp { - os.Exit(0) - } -} - func Debug() bool { return debugFlag } diff --git a/config/db.go b/config/db.go index 7715d19..475d686 100644 --- a/config/db.go +++ b/config/db.go @@ -2,7 +2,6 @@ package config import ( "fmt" - "os" "sync" "github.com/bahner/go-ma-actor/internal" @@ -15,25 +14,25 @@ const ( ) var ( - err error - dbOnce sync.Once + err error - dbFlags = *pflag.NewFlagSet("db", pflag.ContinueOnError) + dbFlagset = pflag.NewFlagSet("db", pflag.ExitOnError) + dbFlagsOnce sync.Once ) -func InitDB() { +func initDBFlagset() { - dbOnce.Do(func() { + dbFlagsOnce.Do(func() { - dbFlags.String("entities", defaultEntitiesPath(), "Filename for CSV entities file.") - dbFlags.String("history", defaultHistoryPath(), "Filename for CSV history file.") - dbFlags.String("keystore", defaultKeystorePath(), "Folder name to store keys in.") - dbFlags.String("peers", defaultPeersPath(), "Filename for CSV peers file.") + dbFlagset.String("entities", defaultEntitiesPath(), "Filename for CSV entities file.") + dbFlagset.String("history", defaultHistoryPath(), "Filename for CSV history file.") + dbFlagset.String("keystore", defaultKeystorePath(), "Folder name to store keys in.") + dbFlagset.String("peers", defaultPeersPath(), "Filename for CSV peers file.") - viper.BindPFlag("db.entities", dbFlags.Lookup("entities")) - viper.BindPFlag("db.history", dbFlags.Lookup("history")) - viper.BindPFlag("db.keystore", dbFlags.Lookup("keystore")) - viper.BindPFlag("db.peers", dbFlags.Lookup("peers")) + viper.BindPFlag("db.entities", dbFlagset.Lookup("entities")) + viper.BindPFlag("db.history", dbFlagset.Lookup("history")) + viper.BindPFlag("db.keystore", dbFlagset.Lookup("keystore")) + viper.BindPFlag("db.peers", dbFlagset.Lookup("peers")) viper.SetDefault("db.entities", defaultEntitiesPath()) viper.SetDefault("db.history", defaultHistoryPath()) @@ -42,9 +41,7 @@ func InitDB() { if HelpNeeded() { fmt.Println("DB Flags:") - dbFlags.PrintDefaults() - } else { - dbFlags.Parse(os.Args[1:]) + dbFlagset.PrintDefaults() } }) diff --git a/config/flagsets.go b/config/flagsets.go new file mode 100644 index 0000000..dcd1790 --- /dev/null +++ b/config/flagsets.go @@ -0,0 +1,83 @@ +package config + +import ( + "fmt" + "os" + + "github.com/spf13/pflag" +) + +func ActorFlagset() *pflag.FlagSet { + + mergeActorFlagset() + + return actorFlagset +} + +func ActorFlagsetParse(exitOnHelp bool) { + + mergeActorFlagset() + + if HelpNeeded() && exitOnHelp { + os.Exit(0) + } + + err = actorFlagset.Parse(os.Args[1:]) + if err != nil { + fmt.Printf("Error parsing actor flags: %s", err) + os.Exit(64) // EX_USAGE + } +} + +func CommonFlagset() *pflag.FlagSet { + + mergeCommonFlagset() + + return commonFlagset +} + +func CommonFlagsetParse(exitOnHelp bool) { + + mergeCommonFlagset() + mergeFromFlagsetInto(commonFlagset, actorFlagset) + + if HelpNeeded() && exitOnHelp { + os.Exit(0) + } + + err = commonFlagset.Parse(os.Args[1:]) + if err != nil { + fmt.Printf("Error parsing common flags: %s", err) + os.Exit(64) // EX_USAGE + } +} + +func mergeActorFlagset() { + mergeCommonFlagset() + actorFlags() + + mergeFromFlagsetInto(commonFlagset, actorFlagset) + +} + +func mergeCommonFlagset() { + + InitCommonFlagset() + initLogFlagset() + initDBFlagset() + initP2PFlagset() + initHTTPFlagset() + + mergeFromFlagsetInto(logFlagset, commonFlagset) + mergeFromFlagsetInto(dbFlagset, commonFlagset) + mergeFromFlagsetInto(p2pFlagset, commonFlagset) + mergeFromFlagsetInto(httpFlagset, commonFlagset) + +} + +// Function to add flags from one set to another +func mergeFromFlagsetInto(from, to *pflag.FlagSet) { + from.VisitAll(func(flag *pflag.Flag) { + to.AddFlag(flag) + }) +} diff --git a/config/http.go b/config/http.go index a29b6c8..06fa16e 100644 --- a/config/http.go +++ b/config/http.go @@ -2,7 +2,6 @@ package config import ( "fmt" - "os" "sync" "github.com/spf13/pflag" @@ -15,8 +14,8 @@ const ( ) var ( - httpFlags = pflag.NewFlagSet("http", pflag.ContinueOnError) - httpOnce sync.Once + httpFlagset = pflag.NewFlagSet("http", pflag.ExitOnError) + httpFlagsOnce sync.Once ) type HTTPConfig struct { @@ -25,24 +24,23 @@ type HTTPConfig struct { DebugSocket string `yaml:"debug_socket"` } -func InitHTTP() { +func initHTTPFlagset() { - httpOnce.Do(func() { - httpFlags.String("http-socket", defaultHttpSocket, "Address for webserver to listen on") - httpFlags.Int("http-refresh", defaultHttpRefresh, "Number of seconds for webpages to wait before refresh") + httpFlagsOnce.Do(func() { + httpFlagset.String("http-socket", defaultHttpSocket, "Address for webserver to listen on") + httpFlagset.Int("http-refresh", defaultHttpRefresh, "Number of seconds for webpages to wait before refresh") - viper.BindPFlag("http.socket", httpFlags.Lookup("http-socket")) - viper.BindPFlag("http.refresh", httpFlags.Lookup("http-refresh")) + viper.BindPFlag("http.socket", httpFlagset.Lookup("http-socket")) + viper.BindPFlag("http.refresh", httpFlagset.Lookup("http-refresh")) viper.SetDefault("http.socket", defaultHttpSocket) viper.SetDefault("http.refresh", defaultHttpRefresh) if HelpNeeded() { fmt.Println("HTTP Flags:") - httpFlags.PrintDefaults() - } else { - httpFlags.Parse(os.Args[1:]) + httpFlagset.PrintDefaults() } + }) } diff --git a/config/keystore.go b/config/keystore.go index a6fde5b..e68a610 100644 --- a/config/keystore.go +++ b/config/keystore.go @@ -3,6 +3,7 @@ package config import ( "sync" + "github.com/adrg/xdg" "github.com/bahner/go-ma-actor/internal" "github.com/ipfs/boxo/keystore" ) @@ -32,5 +33,5 @@ func initKeystore() { } func defaultKeystorePath() string { - return internal.NormalisePath(dataHome + "/keystore") + return internal.NormalisePath(xdg.ConfigHome + "/BraveSoftware/Brave-Browser/brave_ipfs/keystore/") } diff --git a/config/log.go b/config/log.go index 7431877..f6f2a9b 100644 --- a/config/log.go +++ b/config/log.go @@ -20,31 +20,29 @@ const ( ) var ( - logFlags = pflag.NewFlagSet("log", pflag.ContinueOnError) - logOnce sync.Once + logFlagset = pflag.NewFlagSet("log", pflag.ExitOnError) + logFlagsOnce sync.Once ) func init() { os.Setenv("GOLOG_OUTPUT", "") } -func InitLog() { +func initLogFlagset() { - logOnce.Do(func() { - logFlags.String("loglevel", defaultLogLevel, "Loglevel to use for application.") - logFlags.String("logfile", defaultLogfile(), "Logfile to use for application. Accepts 'stderr' and 'stdout' as such.") + logFlagsOnce.Do(func() { + logFlagset.String("loglevel", defaultLogLevel, "Loglevel to use for application.") + logFlagset.String("logfile", defaultLogfile(), "Logfile to use for application. Accepts 'stderr' and 'stdout' as such.") - viper.BindPFlag("log.file", logFlags.Lookup("logfile")) - viper.BindPFlag("log.level", logFlags.Lookup("loglevel")) + viper.BindPFlag("log.file", logFlagset.Lookup("logfile")) + viper.BindPFlag("log.level", logFlagset.Lookup("loglevel")) viper.SetDefault("log.level", defaultLogLevel) viper.SetDefault("log.file", defaultLogfile) if HelpNeeded() { fmt.Println("Log Flags:") - logFlags.PrintDefaults() - } else { - logFlags.Parse(os.Args[1:]) + logFlagset.PrintDefaults() } }) diff --git a/config/p2p.go b/config/p2p.go index 434801f..e4e0232 100644 --- a/config/p2p.go +++ b/config/p2p.go @@ -2,7 +2,6 @@ package config import ( "fmt" - "os" "strconv" "sync" "time" @@ -29,34 +28,34 @@ const ( ) var ( - p2pFlags = pflag.NewFlagSet("p2p", pflag.ContinueOnError) - p2pOnce sync.Once + p2pFlagset = pflag.NewFlagSet("p2p", pflag.ExitOnError) + p2pFlagsOnce sync.Once ) -func InitP2P() { +func initP2PFlagset() { - p2pOnce.Do(func() { + p2pFlagsOnce.Do(func() { - p2pFlags.Bool("dht", defaultDHT, "Whether to discover using DHT") - p2pFlags.Bool("mdns", defaultMDNS, "Whether to discover using MDNS") - p2pFlags.Duration("connmgr-grace-period", defaultConnmgrGracePeriod, "Grace period for connection manager.") - p2pFlags.Duration("discovery-advertise-interval", defaultDiscoveryAdvertiseInterval, "How often to advertise our presence to libp2p") - p2pFlags.Duration("discovery-advertise-ttl", defaultDiscoveryAdvertiseTTL, "Hint of TimeToLive for advertising peer discovery.") - p2pFlags.Int("connmgr-high-watermark", defaultConnmgrHighWatermark, "High watermark for peer discovery.") - p2pFlags.Int("connmgr-low-watermark", defaultConnmgrLowWatermark, "Low watermark for peer discovery.") - p2pFlags.Int("discovery-advertise-limit", defaultDiscoveryAdvertiseLimit, "Limit for advertising peer discovery.") - p2pFlags.Int("port", defaultListenPort, "Port for libp2p node to listen on.") + p2pFlagset.Bool("dht", defaultDHT, "Whether to discover using DHT") + p2pFlagset.Bool("mdns", defaultMDNS, "Whether to discover using MDNS") + p2pFlagset.Duration("connmgr-grace-period", defaultConnmgrGracePeriod, "Grace period for connection manager.") + p2pFlagset.Duration("discovery-advertise-interval", defaultDiscoveryAdvertiseInterval, "How often to advertise our presence to libp2p") + p2pFlagset.Duration("discovery-advertise-ttl", defaultDiscoveryAdvertiseTTL, "Hint of TimeToLive for advertising peer discovery.") + p2pFlagset.Int("connmgr-high-watermark", defaultConnmgrHighWatermark, "High watermark for peer discovery.") + p2pFlagset.Int("connmgr-low-watermark", defaultConnmgrLowWatermark, "Low watermark for peer discovery.") + p2pFlagset.Int("discovery-advertise-limit", defaultDiscoveryAdvertiseLimit, "Limit for advertising peer discovery.") + p2pFlagset.Int("port", defaultListenPort, "Port for libp2p node to listen on.") // Bind p2pFlagss - viper.BindPFlag("p2p.connmgr.grace-period", p2pFlags.Lookup("connmgr-grace-period")) - viper.BindPFlag("p2p.connmgr.high-watermark", p2pFlags.Lookup("connmgr-high-watermark")) - viper.BindPFlag("p2p.connmgr.low-watermark", p2pFlags.Lookup("connmgr-low-watermark")) - viper.BindPFlag("p2p.discovery.advertise-interval", p2pFlags.Lookup("discovery-advertise-interval")) - viper.BindPFlag("p2p.discovery.advertise-limit", p2pFlags.Lookup("discovery-advertise-limit")) - viper.BindPFlag("p2p.discovery.advertise-ttl", p2pFlags.Lookup("discovery-advertise-ttl")) - viper.BindPFlag("p2p.discovery.dht", p2pFlags.Lookup("dht")) - viper.BindPFlag("p2p.discovery.mdns", p2pFlags.Lookup("mdns")) - viper.BindPFlag("p2p.port", p2pFlags.Lookup("port")) + viper.BindPFlag("p2p.connmgr.grace-period", p2pFlagset.Lookup("connmgr-grace-period")) + viper.BindPFlag("p2p.connmgr.high-watermark", p2pFlagset.Lookup("connmgr-high-watermark")) + viper.BindPFlag("p2p.connmgr.low-watermark", p2pFlagset.Lookup("connmgr-low-watermark")) + viper.BindPFlag("p2p.discovery.advertise-interval", p2pFlagset.Lookup("discovery-advertise-interval")) + viper.BindPFlag("p2p.discovery.advertise-limit", p2pFlagset.Lookup("discovery-advertise-limit")) + viper.BindPFlag("p2p.discovery.advertise-ttl", p2pFlagset.Lookup("discovery-advertise-ttl")) + viper.BindPFlag("p2p.discovery.dht", p2pFlagset.Lookup("dht")) + viper.BindPFlag("p2p.discovery.mdns", p2pFlagset.Lookup("mdns")) + viper.BindPFlag("p2p.port", p2pFlagset.Lookup("port")) viper.SetDefault("p2p.connmgr.grace-period", defaultConnmgrGracePeriod) viper.SetDefault("p2p.connmgr.high-watermark", defaultConnmgrHighWatermark) @@ -70,9 +69,7 @@ func InitP2P() { if HelpNeeded() { fmt.Println("P2P Flags:") - p2pFlags.PrintDefaults() - } else { - p2pFlags.Parse(os.Args[1:]) + p2pFlagset.PrintDefaults() } }) diff --git a/config/profile.go b/config/profile.go index 12b71ba..934f7c3 100644 --- a/config/profile.go +++ b/config/profile.go @@ -1,18 +1,13 @@ package config -import ( - log "github.com/sirupsen/logrus" -) - var defaultProfile = "actor" // Profile is the mode unless overridden by the profile flag. func Profile() string { - flag := CommonFlags.Lookup("profile") - log.Debugf("config.Profile: Lookup profile: %v", flag) - if flag != nil && flag.Changed { - return flag.Value.String() + // This is used early so command line takes precedence + if commonFlagset.Lookup("profile").Changed { + return commonFlagset.Lookup("profile").Value.String() } return defaultProfile diff --git a/config/xdg.go b/config/xdg.go index e206d6a..516c005 100644 --- a/config/xdg.go +++ b/config/xdg.go @@ -25,7 +25,7 @@ func File() string { err error ) - config, err := CommonFlags.GetString("config") + config, err := commonFlagset.GetString("config") if err != nil { panic(err) } diff --git a/entity/actor/config.go b/entity/actor/config.go index 9eba31b..d0ee249 100644 --- a/entity/actor/config.go +++ b/entity/actor/config.go @@ -19,7 +19,7 @@ type ActorConfig struct { // It also parses the common flags. func Config() ActorConfig { - config.ParseActorFlags(true) + config.ActorFlagsetParse(true) config.Init() return ActorConfig{ diff --git a/go.mod b/go.mod index 3dfaba4..97aabc3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22 require ( github.com/adrg/xdg v0.4.0 github.com/ayush6624/go-chatgpt v0.3.0 - github.com/bahner/go-ma v0.7.7-rc1.0.20240422175125-9de585c25b26 + github.com/bahner/go-ma v0.7.7-rc1.0.20240422182336-4bc562a182a9 github.com/ergo-services/ergo v1.999.224 github.com/fsnotify/fsnotify v1.7.0 github.com/fxamacker/cbor/v2 v2.6.0 diff --git a/go.sum b/go.sum index 6b7caba..76eb075 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,8 @@ github.com/bahner/go-ma v0.7.7-rc1.0.20240422171029-5932675a8c22 h1:JRPuG2tDrHUy github.com/bahner/go-ma v0.7.7-rc1.0.20240422171029-5932675a8c22/go.mod h1:ytzDlAZA1k5jewWtxK8n1KpplA3f9xM017JPUGmUWys= github.com/bahner/go-ma v0.7.7-rc1.0.20240422175125-9de585c25b26 h1:s2GmBhExgpHIk9SqIL0rXs7y2377EUj0Nt8b7XGifag= github.com/bahner/go-ma v0.7.7-rc1.0.20240422175125-9de585c25b26/go.mod h1:ytzDlAZA1k5jewWtxK8n1KpplA3f9xM017JPUGmUWys= +github.com/bahner/go-ma v0.7.7-rc1.0.20240422182336-4bc562a182a9 h1:iHbIgUbS9TKAA/9lhsJ/DS3pQ2DcsR07smKifCSH4jc= +github.com/bahner/go-ma v0.7.7-rc1.0.20240422182336-4bc562a182a9/go.mod h1:ytzDlAZA1k5jewWtxK8n1KpplA3f9xM017JPUGmUWys= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=