// newConfigParser returns a new command line flags parser. func newConfigParser(cfg *config, so *serviceOptions, options flags.Options) *flags.Parser { parser := flags.NewParser(cfg, options) if runtime.GOOS == "windows" { parser.AddGroup("Service Options", "Service Options", so) } return parser }
func main() { cfg := config{ Years: 10, Organization: "gencerts", } parser := flags.NewParser(&cfg, flags.Default) _, err := parser.Parse() if err != nil { if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp { parser.WriteHelp(os.Stderr) } return } if cfg.Directory == "" { var err error cfg.Directory, err = os.Getwd() if err != nil { fmt.Fprintf(os.Stderr, "no directory specified and cannot get working directory\n") os.Exit(1) } } cfg.Directory = cleanAndExpandPath(cfg.Directory) certFile := filepath.Join(cfg.Directory, "rpc.cert") keyFile := filepath.Join(cfg.Directory, "rpc.key") if !cfg.Force { if fileExists(certFile) || fileExists(keyFile) { fmt.Fprintf(os.Stderr, "%v: certificate and/or key files exist; use -f to force\n", cfg.Directory) os.Exit(1) } } validUntil := time.Now().Add(time.Duration(cfg.Years) * 365 * 24 * time.Hour) cert, key, err := btcutil.NewTLSCertPair(cfg.Organization, validUntil, cfg.ExtraHosts) if err != nil { fmt.Fprintf(os.Stderr, "cannot generate certificate pair: %v\n", err) os.Exit(1) } // Write cert and key files. if err = ioutil.WriteFile(certFile, cert, 0666); err != nil { fmt.Fprintf(os.Stderr, "cannot write cert: %v\n", err) os.Exit(1) } if err = ioutil.WriteFile(keyFile, key, 0600); err != nil { os.Remove(certFile) fmt.Fprintf(os.Stderr, "cannot write key: %v\n", err) os.Exit(1) } }
// loadConfig initializes and parses the config using command line options. func loadConfig() (*config, []string, error) { // Default config. cfg := config{ DataDir: defaultDataDir, DbType: defaultDbType, InFile: defaultDataFile, Progress: defaultProgress, } // Parse command line options. parser := flags.NewParser(&cfg, flags.Default) remainingArgs, err := parser.Parse() if err != nil { if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp { parser.WriteHelp(os.Stderr) } return nil, nil, err } // Multiple networks can't be selected simultaneously. funcName := "loadConfig" numNets := 0 // Count number of network flags passed; assign active network params // while we're at it if cfg.TestNet3 { numNets++ activeNetParams = &chaincfg.TestNet3Params } if cfg.RegressionTest { numNets++ activeNetParams = &chaincfg.RegressionNetParams } if cfg.SimNet { numNets++ activeNetParams = &chaincfg.SimNetParams } if numNets > 1 { str := "%s: The testnet, regtest, and simnet params can't be " + "used together -- choose one of the three" err := fmt.Errorf(str, funcName) fmt.Fprintln(os.Stderr, err) parser.WriteHelp(os.Stderr) return nil, nil, err } // Validate database type. if !validDbType(cfg.DbType) { str := "%s: The specified database type [%v] is invalid -- " + "supported types %v" err := fmt.Errorf(str, "loadConfig", cfg.DbType, knownDbTypes) fmt.Fprintln(os.Stderr, err) parser.WriteHelp(os.Stderr) return nil, nil, err } // Append the network type to the data directory so it is "namespaced" // per network. In addition to the block database, there are other // pieces of data that are saved to disk such as address manager state. // All data is specific to a network, so namespacing the data directory // means each individual piece of serialized data does not have to // worry about changing names per network and such. cfg.DataDir = filepath.Join(cfg.DataDir, netName(activeNetParams)) // Ensure the specified block file exists. if !fileExists(cfg.InFile) { str := "%s: The specified block file [%v] does not exist" err := fmt.Errorf(str, "loadConfig", cfg.InFile) fmt.Fprintln(os.Stderr, err) parser.WriteHelp(os.Stderr) return nil, nil, err } return &cfg, remainingArgs, nil }
func main() { cfg := config{ DbType: "leveldb", DataDir: defaultDataDir, } parser := flags.NewParser(&cfg, flags.Default) _, err := parser.Parse() if err != nil { if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp { parser.WriteHelp(os.Stderr) } return } backendLogger := btclog.NewDefaultBackendLogger() defer backendLogger.Flush() log = btclog.NewSubsystemLogger(backendLogger, "") database.UseLogger(log) // Multiple networks can't be selected simultaneously. funcName := "main" numNets := 0 // Count number of network flags passed; assign active network params // while we're at it if cfg.TestNet3 { numNets++ activeNetParams = &chaincfg.TestNet3Params } if cfg.RegressionTest { numNets++ activeNetParams = &chaincfg.RegressionNetParams } if cfg.SimNet { numNets++ activeNetParams = &chaincfg.SimNetParams } if numNets > 1 { str := "%s: The testnet, regtest, and simnet params can't be " + "used together -- choose one of the three" err := fmt.Errorf(str, funcName) fmt.Fprintln(os.Stderr, err) parser.WriteHelp(os.Stderr) return } cfg.DataDir = filepath.Join(cfg.DataDir, netName(activeNetParams)) blockDbNamePrefix := "blocks" dbName := blockDbNamePrefix + "_" + cfg.DbType if cfg.DbType == "sqlite" { dbName = dbName + ".db" } dbPath := filepath.Join(cfg.DataDir, dbName) log.Infof("loading db") db, err := database.OpenDB(cfg.DbType, dbPath) if err != nil { log.Warnf("db open failed: %v", err) return } defer db.Close() log.Infof("db load complete") _, height, err := db.NewestSha() log.Infof("loaded block height %v", height) sha, err := getSha(db, cfg.ShaString) if err != nil { log.Infof("Invalid block hash %v", cfg.ShaString) return } err = db.DropAfterBlockBySha(&sha) if err != nil { log.Warnf("failed %v", err) } }
// loadConfig initializes and parses the config using a config file and command // line options. // // The configuration proceeds as follows: // 1) Start with a default config with sane settings // 2) Pre-parse the command line to check for an alternative config file // 3) Load configuration file overwriting defaults with any specified options // 4) Parse CLI options and overwrite/add any specified options // // The above results in functioning properly without any config settings // while still allowing the user to override settings with config files and // command line options. Command line options always take precedence. func loadConfig() (*config, []string, error) { // Default config. cfg := config{ ConfigFile: defaultConfigFile, RPCServer: defaultRPCServer, RPCCert: defaultRPCCertFile, } // Create the home directory if it doesn't already exist. err := os.MkdirAll(btcdHomeDir, 0700) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(-1) } // Pre-parse the command line options to see if an alternative config // file, the version flag, or the list commands flag was specified. Any // errors aside from the help message error can be ignored here since // they will be caught by the final parse below. preCfg := cfg preParser := flags.NewParser(&preCfg, flags.HelpFlag) _, err = preParser.Parse() if err != nil { if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp { fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "The special parameter `-` "+ "indicates that a parameter should be read "+ "from the\nnext unread line from standard "+ "input.") return nil, nil, err } } // Show the version and exit if the version flag was specified. appName := filepath.Base(os.Args[0]) appName = strings.TrimSuffix(appName, filepath.Ext(appName)) usageMessage := fmt.Sprintf("Use %s -h to show options", appName) if preCfg.ShowVersion { fmt.Println(appName, "version", version()) os.Exit(0) } // Show the available commands and exit if the associated flag was // specified. if preCfg.ListCommands { listCommands() os.Exit(0) } // Load additional config from file. parser := flags.NewParser(&cfg, flags.Default) err = flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile) if err != nil { if _, ok := err.(*os.PathError); !ok { fmt.Fprintf(os.Stderr, "Error parsing config file: %v\n", err) fmt.Fprintln(os.Stderr, usageMessage) return nil, nil, err } } // Parse command line options again to ensure they take precedence. remainingArgs, err := parser.Parse() if err != nil { if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp { fmt.Fprintln(os.Stderr, usageMessage) } return nil, nil, err } // Multiple networks can't be selected simultaneously. numNets := 0 if cfg.TestNet3 { numNets++ } if cfg.SimNet { numNets++ } if numNets > 1 { str := "%s: The testnet and simnet params can't be used " + "together -- choose one of the two" err := fmt.Errorf(str, "loadConfig") fmt.Fprintln(os.Stderr, err) return nil, nil, err } // Override the RPC certificate if the --wallet flag was specified and // the user did not specify one. if cfg.Wallet && cfg.RPCCert == defaultRPCCertFile { cfg.RPCCert = defaultWalletCertFile } // Handle environment variable expansion in the RPC certificate path. cfg.RPCCert = cleanAndExpandPath(cfg.RPCCert) // Add default port to RPC server based on --testnet and --wallet flags // if needed. cfg.RPCServer = normalizeAddress(cfg.RPCServer, cfg.TestNet3, cfg.SimNet, cfg.Wallet) return &cfg, remainingArgs, nil }