|
| 1 | +// Copyright (C) 2017-present Arctic Ice Studio <[email protected]> |
| 2 | +// Copyright (C) 2017-present Sven Greb <[email protected]> |
| 3 | +// |
| 4 | +// Project: snowsaw |
| 5 | +// Repository: https://github.com/arcticicestudio/snowsaw |
| 6 | +// License: MIT |
| 7 | + |
| 8 | +// Author: Arctic Ice Studio <[email protected]> |
| 9 | +// Author: Sven Greb <[email protected]> |
| 10 | +// Since: 0.4.0 |
| 11 | + |
| 12 | +// Package snowsaw provides the root command of the application and bootstraps the startup. |
| 13 | +package snowsaw |
| 14 | + |
| 15 | +import ( |
| 16 | + "os" |
| 17 | + "strings" |
| 18 | + |
| 19 | + "github.com/fatih/color" |
| 20 | + "github.com/spf13/cobra" |
| 21 | + |
| 22 | + "github.com/arcticicestudio/snowsaw/cmd/snowsaw/info" |
| 23 | + "github.com/arcticicestudio/snowsaw/pkg/config" |
| 24 | + "github.com/arcticicestudio/snowsaw/pkg/config/builder" |
| 25 | + "github.com/arcticicestudio/snowsaw/pkg/config/source/file" |
| 26 | + "github.com/arcticicestudio/snowsaw/pkg/prt" |
| 27 | +) |
| 28 | + |
| 29 | +var ( |
| 30 | + // debug indicates if the `debug` flag has been set to enable configure the logging for the debug scope. |
| 31 | + debug bool |
| 32 | + // explicitConfigFilePath stores the path to the application configuration file when the `config` flag is specified. |
| 33 | + explicitConfigFilePath string |
| 34 | +) |
| 35 | + |
| 36 | +// rootCmd is the root command of the application. |
| 37 | +var rootCmd = &cobra.Command{ |
| 38 | + Use: config.ProjectName, |
| 39 | + Short: "A lightweight, plugin-driven and dynamic dotfiles bootstrapper.", |
| 40 | + Run: func(cmd *cobra.Command, args []string) { |
| 41 | + if err := cmd.Help(); err != nil { |
| 42 | + prt.Errorf("Failed to run %s: %v", config.ProjectName, err) |
| 43 | + os.Exit(1) |
| 44 | + } |
| 45 | + }, |
| 46 | +} |
| 47 | + |
| 48 | +// Run is the main application function that adds all child commands to the root command and sets flags appropriately. |
| 49 | +// This is called by `main.main()` and only needs to be run once for the root command. |
| 50 | +func Run() { |
| 51 | + // Disable verbose errors to provide custom formatted CLI output via application-wide printer. |
| 52 | + rootCmd.SilenceErrors = true |
| 53 | + |
| 54 | + // Run the application with the given commands, flags and arguments and exit on any (downstream) error. |
| 55 | + if err := rootCmd.Execute(); err != nil { |
| 56 | + prt.Errorf(err.Error()) |
| 57 | + os.Exit(1) |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +func init() { |
| 62 | + // Specify the functions to be run before each command gets executed. |
| 63 | + cobra.OnInitialize(initDebugScope, initConfig, initPrinter) |
| 64 | + |
| 65 | + // Define global application flags. |
| 66 | + rootCmd.PersistentFlags().StringVar(&explicitConfigFilePath, "config", "", "set the configuration file") |
| 67 | + rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "enable debug information output") |
| 68 | + |
| 69 | + // Set the app version information for the automatically generated `version` flag. |
| 70 | + rootCmd.Version = color.CyanString(config.Version) |
| 71 | + rootCmd.SetVersionTemplate(`{{printf "%s\n" .Version}}`) |
| 72 | + |
| 73 | + // Create and register all subcommands. |
| 74 | + rootCmd.AddCommand(info.NewInfoCmd()) |
| 75 | +} |
| 76 | + |
| 77 | +// initConfig searches and loads either the default application configuration file paths or the explicit file at the |
| 78 | +// given path specified through the global `config` flag. |
| 79 | +func initConfig() { |
| 80 | + if explicitConfigFilePath != "" { |
| 81 | + if err := builder.Load(file.NewFile(explicitConfigFilePath)).Into(&config.AppConfig); err != nil { |
| 82 | + prt.Errorf("while loading custom application configuration file:\n%v", err) |
| 83 | + os.Exit(1) |
| 84 | + } |
| 85 | + } else { |
| 86 | + b := builder.Load(config.AppConfigPaths...) |
| 87 | + if len(b.Files) == 0 { |
| 88 | + prt.Debugf("No configuration files found, using default application configuration.") |
| 89 | + } |
| 90 | + if err := b.Into(&config.AppConfig); err != nil { |
| 91 | + prt.Errorf("while loading application configuration files:\n%v", err) |
| 92 | + os.Exit(1) |
| 93 | + } |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +// initDebugScope configures the application when run with debug scope. |
| 98 | +func initDebugScope() { |
| 99 | + if debug { |
| 100 | + prt.SetVerbosityLevel(prt.DebugVerbosity) |
| 101 | + } |
| 102 | +} |
| 103 | + |
| 104 | +// setPrinterVerbosityLevel configures the global CLI printer like the verbosity level. |
| 105 | +func initPrinter() { |
| 106 | + lvl, err := prt.ParseVerbosityLevel(strings.ToUpper(config.AppConfig.LogLevel)) |
| 107 | + if err != nil { |
| 108 | + prt.Debugf("Error while parsing log level from configuration: %v", err) |
| 109 | + prt.Debugf("Using default INFO level as fallback") |
| 110 | + prt.SetVerbosityLevel(prt.InfoVerbosity) |
| 111 | + } else { |
| 112 | + prt.Debugf("Using configured logger level: %s", strings.ToUpper(config.AppConfig.LogLevel)) |
| 113 | + prt.SetVerbosityLevel(lvl) |
| 114 | + } |
| 115 | +} |
0 commit comments