From 07096ef9bdec839b4f8fe4e12e8b71a0c6792bab Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Mon, 11 Sep 2023 18:18:17 +0200 Subject: [PATCH 1/9] fix: apply smart mode logic only to supported commands fixes #82 --- cmd/all.go | 3 ++ cmd/render.go | 3 ++ cmd/root.go | 105 +++++++++++++++++++++++++------------------------- cmd/sync.go | 9 +++-- go.mod | 2 +- go.sum | 2 - 6 files changed, 66 insertions(+), 58 deletions(-) diff --git a/cmd/all.go b/cmd/all.go index e6cdb468..ba80c8a1 100644 --- a/cmd/all.go +++ b/cmd/all.go @@ -12,6 +12,9 @@ func init() { Use: "all", Short: "Run sync and render", Long: "Run sync and render", + Annotations: map[string]string{ + ANNOTATION_SMART_MODE: ANNOTATION_TRUE, + }, Run: func(cmd *cobra.Command, args []string) { g := myks.New(".") diff --git a/cmd/render.go b/cmd/render.go index 0cb3319d..e9afad0f 100644 --- a/cmd/render.go +++ b/cmd/render.go @@ -12,6 +12,9 @@ func init() { Use: "render", Short: "Render manifests", Long: "Render manifests", + Annotations: map[string]string{ + ANNOTATION_SMART_MODE: ANNOTATION_TRUE, + }, Run: func(cmd *cobra.Command, args []string) { g := myks.New(".") diff --git a/cmd/root.go b/cmd/root.go index a421e486..0ebc5fa3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,6 +16,11 @@ import ( "github.com/mykso/myks/internal/myks" ) +const ( + ANNOTATION_SMART_MODE = "feat:smart-mode" + ANNOTATION_TRUE = "true" +) + var ( cfgFile string targetEnvironments []string @@ -26,7 +31,7 @@ var ( var rootCmd = &cobra.Command{ Use: "myks", Short: "Myks helps to manage configuration for kubernetes clusters", - Long: `Myks fetches K8s workloads from a variety of sources, e.g. Helm charts or Git Repositories. It renders their respective yaml files to the file system in a structure of environments and their applications. + Long: `Myks fetches K8s workloads from a variety of sources, e.g. Helm charts or Git Repositories. It renders their respective yaml files to the file system in a structure of environments and their applications. It supports prototype applications that can be shared between environments and inheritance of configuration from parent environments to their "children". @@ -37,57 +42,6 @@ Myks supports two positional arguments: If you do not provide any positional arguments, myks will run in "Smart Mode". In Smart Mode, myks will only render environments and applications that have changed since the last run. `, - PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { - // Check positional arguments: - // 1. Comma-separated list of environment search paths or ALL to search everywhere (default: ALL) - // 2. Comma-separated list of application names or none to process all applications (default: none) - - targetEnvironments = nil - targetApplications = nil - - onlyArgs := args - - for _, subcmd := range cmd.Commands() { - if subcmd.Name() == args[0] { - onlyArgs = args[1:] - break - } - } - - switch len(onlyArgs) { - case 0: - // smart mode requires instantiation of globe object to get the list of environments - // the globe object will not be used later in the process. It is only used to get the list of all environments and their apps. - globeAllEnvsAndApps := myks.New(".") - targetEnvironments, targetApplications, err = globeAllEnvsAndApps.InitSmartMode() - if err != nil { - log.Warn().Err(err).Msg("Unable to run Smart Mode. Rendering everything.") - } - if targetEnvironments == nil && targetApplications == nil { - log.Warn().Msg("Smart Mode did not find any changes. Existing.") - os.Exit(0) - } - case 1: - if onlyArgs[0] != "ALL" { - targetEnvironments = strings.Split(onlyArgs[0], ",") - } - case 2: - if onlyArgs[0] != "ALL" { - targetEnvironments = strings.Split(onlyArgs[0], ",") - } - if onlyArgs[1] != "ALL" { - targetApplications = strings.Split(onlyArgs[1], ",") - } - default: - err := errors.New("Too many positional arguments") - log.Error().Err(err).Msg("Unable to parse positional arguments") - return err - } - - log.Debug().Strs("environments", targetEnvironments).Strs("applications", targetApplications).Msg("Parsed arguments") - - return nil - }, } func init() { @@ -103,6 +57,53 @@ func init() { } rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is the first .myks.yaml up the directory tree)") + + rootCmd.PersistentPreRunE = detectTargetEnvsAndApps +} + +func detectTargetEnvsAndApps(cmd *cobra.Command, args []string) (err error) { + // Check positional arguments for Smart Mode: + // 1. Comma-separated list of environment search paths or ALL to search everywhere (default: ALL) + // 2. Comma-separated list of application names or none to process all applications (default: none) + + if cmd.Annotations[ANNOTATION_SMART_MODE] != ANNOTATION_TRUE { + log.Debug().Msg("Smart Mode is not supported for this command.") + return + } + + switch len(args) { + case 0: + // smart mode requires instantiation of globe object to get the list of environments + // the globe object will not be used later in the process. It is only used to get the list of all environments and their apps. + globeAllEnvsAndApps := myks.New(".") + targetEnvironments, targetApplications, err = globeAllEnvsAndApps.InitSmartMode() + if err != nil { + log.Warn().Err(err).Msg("Unable to run Smart Mode. Rendering everything.") + } + if targetEnvironments == nil && targetApplications == nil { + log.Warn().Msg("Smart Mode did not find any changes. Exiting.") + os.Exit(0) + } + case 1: + if args[0] != "ALL" { + targetEnvironments = strings.Split(args[0], ",") + } + case 2: + if args[0] != "ALL" { + targetEnvironments = strings.Split(args[0], ",") + } + if args[1] != "ALL" { + targetApplications = strings.Split(args[1], ",") + } + default: + err := errors.New("Too many positional arguments") + log.Error().Err(err).Msg("Unable to parse positional arguments") + return err + } + + log.Debug().Strs("environments", targetEnvironments).Strs("applications", targetApplications).Msg("Parsed arguments") + + return nil } func initConfig() { diff --git a/cmd/sync.go b/cmd/sync.go index c4848059..bd48048a 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -11,11 +11,14 @@ func init() { cmd := &cobra.Command{ Use: "sync", Short: "Sync vendir configs", - Long: `Sync vendir configs. This will run vendir sync for all applications. + Long: `Sync vendir configs. This will run vendir sync for all applications. -Authentication against protected repositories is achieved with environment variables prefixed with "VENDIR_SECRET_". -For example, if you reference a secret named "mycreds" in your vendir.yaml, you need to export the variables "VENDIR_SECRET_MYCREDS_USERNAME" and +Authentication against protected repositories is achieved with environment variables prefixed with "VENDIR_SECRET_". +For example, if you reference a secret named "mycreds" in your vendir.yaml, you need to export the variables "VENDIR_SECRET_MYCREDS_USERNAME" and "VENDIR_SECRET_MYCREDS_PASSWORD" in your environment.`, + Annotations: map[string]string{ + ANNOTATION_SMART_MODE: ANNOTATION_TRUE, + }, Run: func(cmd *cobra.Command, args []string) { log.Info().Msg("Syncing vendir configs") g := myks.New(".") diff --git a/go.mod b/go.mod index 517b8829..fb5ebbc1 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/rs/zerolog v1.29.1 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.16.0 + golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 golang.org/x/sync v0.3.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -26,7 +27,6 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect golang.org/x/sys v0.11.0 // indirect golang.org/x/text v0.9.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect diff --git a/go.sum b/go.sum index 6d8960e3..e75efacc 100644 --- a/go.sum +++ b/go.sum @@ -329,8 +329,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= From ace13adf183640ade0bb77e1a48dd63b0d417389 Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Mon, 11 Sep 2023 18:38:12 +0200 Subject: [PATCH 2/9] fix: create myks data schema file on init and on every run This will ensure that the data schema file is always up to date and that it is always present. --- internal/myks/globe.go | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/internal/myks/globe.go b/internal/myks/globe.go index 9261446e..da3153be 100644 --- a/internal/myks/globe.go +++ b/internal/myks/globe.go @@ -156,17 +156,7 @@ func (g *Globe) Init(asyncLevel int, searchPaths []string, applicationNames []st g.extraYttPaths = append(g.extraYttPaths, yttLibraryDir) } - dataSchemaFileName := filepath.Join(g.RootDir, g.ServiceDirName, g.TempDirName, g.DataSchemaFileName) - if _, err := os.Stat(dataSchemaFileName); err != nil { - log.Warn().Msg("Unable to find data schema file, creating one") - if err := os.MkdirAll(filepath.Dir(dataSchemaFileName), 0o750); err != nil { - log.Fatal().Err(err).Msg("Unable to create data schema file directory") - } - if err := os.WriteFile(dataSchemaFileName, dataSchema, 0o600); err != nil { - log.Fatal().Err(err).Msg("Unable to create data schema file") - } - } - g.extraYttPaths = append(g.extraYttPaths, dataSchemaFileName) + g.extraYttPaths = append(g.extraYttPaths, g.createDataSchemaFile()) if configFileName, err := g.dumpConfigAsYaml(); err != nil { log.Warn().Err(err).Msg("Unable to dump config as yaml") @@ -300,6 +290,8 @@ func (g *Globe) createBaseFileStructure(force bool) error { } } + g.createDataSchemaFile() + if err := os.MkdirAll(envDir, 0o750); err != nil { return err } @@ -319,6 +311,22 @@ func (g *Globe) createBaseFileStructure(force bool) error { return nil } +func (g *Globe) createDataSchemaFile() string { + dataSchemaFileName := filepath.Join(g.RootDir, g.ServiceDirName, g.TempDirName, g.DataSchemaFileName) + if _, err := os.Stat(dataSchemaFileName); err != nil { + log.Debug().Msg("Unable to find data schema file, creating one") + if err := os.MkdirAll(filepath.Dir(dataSchemaFileName), 0o750); err != nil { + log.Fatal().Err(err).Msg("Unable to create data schema file directory") + } + } else { + log.Debug().Msg("Overwriting existing data schema file") + } + if err := os.WriteFile(dataSchemaFileName, dataSchema, 0o600); err != nil { + log.Fatal().Err(err).Msg("Unable to create data schema file") + } + return dataSchemaFileName +} + func (g *Globe) createSamplePrototypes() error { protoDir := filepath.Join(g.RootDir, g.PrototypesDir) return copyFileSystemToPath(prototypesFs, "assets/prototypes", protoDir) From c0689af259dbafb5c52a464c60839ab1b870f8b6 Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Mon, 11 Sep 2023 18:57:45 +0200 Subject: [PATCH 3/9] fix: init Globe core attributes earlier --- internal/myks/globe.go | 15 ++++++++------- internal/myks/smart_mode.go | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/myks/globe.go b/internal/myks/globe.go index da3153be..f590a651 100644 --- a/internal/myks/globe.go +++ b/internal/myks/globe.go @@ -143,13 +143,6 @@ func New(rootDir string) *Globe { if err := g.setGitRepoBranch(); err != nil { log.Warn().Err(err).Msg("Unable to set git repo branch") } - log.Debug().Interface("globe", g).Msg("Globe config") - return g -} - -func (g *Globe) Init(asyncLevel int, searchPaths []string, applicationNames []string) error { - g.SearchPaths = searchPaths - g.ApplicationNames = applicationNames yttLibraryDir := filepath.Join(g.RootDir, g.YttLibraryDirName) if _, err := os.Stat(yttLibraryDir); err == nil { @@ -164,6 +157,14 @@ func (g *Globe) Init(asyncLevel int, searchPaths []string, applicationNames []st g.extraYttPaths = append(g.extraYttPaths, configFileName) } + log.Debug().Interface("globe", g).Msg("Globe config") + return g +} + +func (g *Globe) Init(asyncLevel int, searchPaths []string, applicationNames []string) error { + g.SearchPaths = searchPaths + g.ApplicationNames = applicationNames + g.collectEnvironments(searchPaths) return process(asyncLevel, g.environments, func(item interface{}) error { diff --git a/internal/myks/smart_mode.go b/internal/myks/smart_mode.go index 89b17e5d..1772ccea 100644 --- a/internal/myks/smart_mode.go +++ b/internal/myks/smart_mode.go @@ -44,7 +44,7 @@ func (g *Globe) InitSmartMode() ([]string, []string, error) { err := process(0, g.environments, func(item interface{}) error { env, ok := item.(*Environment) if !ok { - return fmt.Errorf("unable to cast item to *Environment") + return fmt.Errorf("Unable to cast item to *Environment") } return env.initEnvData() }) From 56b9d809243d380334b5ffe640bd6549c7278db3 Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Mon, 11 Sep 2023 21:36:10 +0200 Subject: [PATCH 4/9] fix: accept configuration from environment for keys containing dashes --- cmd/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/root.go b/cmd/root.go index 0ebc5fa3..d964efcb 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -108,7 +108,7 @@ func detectTargetEnvsAndApps(cmd *cobra.Command, args []string) (err error) { func initConfig() { viper.SetEnvPrefix("MYKS") - viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) viper.AutomaticEnv() if cfgFile != "" { From f4b838d1e91e56801059530c78d9d8ffcf6d7732 Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Mon, 11 Sep 2023 21:51:36 +0200 Subject: [PATCH 5/9] refactor: extract myks config name parts to constants --- cmd/root.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index d964efcb..1072d3b2 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -19,6 +19,8 @@ import ( const ( ANNOTATION_SMART_MODE = "feat:smart-mode" ANNOTATION_TRUE = "true" + MYKS_CONFIG_NAME = ".myks" + MYKS_CONFIG_TYPE = "yaml" ) var ( @@ -56,7 +58,8 @@ func init() { log.Fatal().Err(err).Msg("Unable to bind flags") } - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is the first .myks.yaml up the directory tree)") + configHelp := fmt.Sprintf("config file (default is the first %s.%s up the directory tree)", MYKS_CONFIG_NAME, MYKS_CONFIG_TYPE) + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", configHelp) rootCmd.PersistentPreRunE = detectTargetEnvsAndApps } @@ -115,8 +118,8 @@ func initConfig() { viper.SetConfigFile(cfgFile) } else { viper.AddConfigPath(".") - viper.SetConfigName(".myks") - viper.SetConfigType("yaml") + viper.SetConfigName(MYKS_CONFIG_NAME) + viper.SetConfigType(MYKS_CONFIG_TYPE) // Add all parent directories to the config search path dir, _ := os.Getwd() From 79bd9607784360264539e0bd075c40a9399aa858 Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Mon, 11 Sep 2023 21:54:47 +0200 Subject: [PATCH 6/9] feat: add command to print config --- cmd/print-config.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 cmd/print-config.go diff --git a/cmd/print-config.go b/cmd/print-config.go new file mode 100644 index 00000000..c3faad3b --- /dev/null +++ b/cmd/print-config.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "fmt" + + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" + "github.com/spf13/viper" + yaml "gopkg.in/yaml.v3" +) + +func init() { + cmd := &cobra.Command{ + Use: "print-config", + Short: "Print myks configuration", + Long: "Print myks configuration", + Run: func(cmd *cobra.Command, args []string) { + c := viper.AllSettings() + bs, err := yaml.Marshal(c) + if err != nil { + log.Fatal().Err(err).Msg("Failed to marshal config") + } + fmt.Printf("---\n%s\n", bs) + }, + } + rootCmd.AddCommand(cmd) +} From 4b7c737236cbfdf9a91b003abe4959dc130054fa Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Mon, 11 Sep 2023 21:55:09 +0200 Subject: [PATCH 7/9] chore: format long string --- cmd/root.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/root.go b/cmd/root.go index 1072d3b2..85927bf9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -104,7 +104,10 @@ func detectTargetEnvsAndApps(cmd *cobra.Command, args []string) (err error) { return err } - log.Debug().Strs("environments", targetEnvironments).Strs("applications", targetApplications).Msg("Parsed arguments") + log.Debug(). + Strs("environments", targetEnvironments). + Strs("applications", targetApplications). + Msg("Parsed arguments") return nil } From 8acc308d0ab224e650b4a66f21dd8c2325c7d923 Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Mon, 11 Sep 2023 22:06:54 +0200 Subject: [PATCH 8/9] chore: improve help --- cmd/root.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 85927bf9..9ca5ee6d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -48,8 +48,11 @@ If you do not provide any positional arguments, myks will run in "Smart Mode". I func init() { cobra.OnInitialize(initConfig) - rootCmd.PersistentFlags().StringP("log-level", "l", "info", "Set the logging level") - rootCmd.PersistentFlags().IntVarP(&asyncLevel, "async", "a", 0, "Sets the number of concurrent processed applications. The default is no limit.") + + rootCmd.PersistentFlags().StringP("log-level", "l", "info", "set the logging level") + + asyncHelp := "sets the number of applications to be processed in parallel\nthe default (0) is no limit" + rootCmd.PersistentFlags().IntVarP(&asyncLevel, "async", "a", 0, asyncHelp) if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { log.Fatal().Err(err).Msg("Unable to bind flags") From 9cd9166c10df94bc18b304fa3fe3ba71e8ac1bb3 Mon Sep 17 00:00:00 2001 From: German Lashevich Date: Tue, 12 Sep 2023 00:13:15 +0200 Subject: [PATCH 9/9] feat: print initial configs --- cmd/init.go | 26 +++++++++++- go.mod | 4 ++ go.sum | 7 +++ internal/myks/assets/myks_config.yaml | 7 +++ internal/myks/globe.go | 61 ++++++++++++++++++++++----- internal/myks/util.go | 18 ++++++++ 6 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 internal/myks/assets/myks_config.yaml diff --git a/cmd/init.go b/cmd/init.go index 52186895..5fe51abf 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -20,7 +20,17 @@ func init() { log.Fatal().Err(err).Msg("Failed to read flag") } - if err := myks.New(".").Bootstrap(force); errors.Is(err, myks.ErrNotClean) { + onlyPrint, err := cmd.Flags().GetBool("print") + if err != nil { + log.Fatal().Err(err).Msg("Failed to read flag") + } + + components, err := cmd.Flags().GetStringSlice("components") + if err != nil { + log.Fatal().Err(err).Msg("Failed to read flag") + } + + if err := myks.New(".").Bootstrap(force, onlyPrint, components); errors.Is(err, myks.ErrNotClean) { log.Error().Msg("Directory not empty. Use --force to overwrite data.") } else if err != nil { log.Fatal().Err(err).Msg("Failed to initialize project") @@ -29,5 +39,19 @@ func init() { } cmd.Flags().BoolP("force", "f", false, "overwrite existing data") + + printHelp := "print configuration instead of creating files\n" + + "applicable only to the following components: gitingore, config, schema" + cmd.Flags().Bool("print", false, printHelp) + + componentsDefault := []string{ + "config", + "environments", + "gitignore", + "prototypes", + "schema", + } + cmd.Flags().StringSlice("components", componentsDefault, "components to initialize") + rootCmd.AddCommand(cmd) } diff --git a/go.mod b/go.mod index fb5ebbc1..b2271bde 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,21 @@ module github.com/mykso/myks go 1.20 require ( + github.com/alecthomas/chroma v0.10.0 github.com/creasty/defaults v1.7.0 + github.com/logrusorgru/aurora/v4 v4.0.0 github.com/pmezard/go-difflib v1.0.0 github.com/rs/zerolog v1.29.1 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.16.0 golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 golang.org/x/sync v0.3.0 + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 gopkg.in/yaml.v3 v3.0.1 ) require ( + github.com/dlclark/regexp2 v1.4.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index e75efacc..c3e98a7e 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= +github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -53,6 +55,8 @@ github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbD github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= +github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -138,6 +142,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/logrusorgru/aurora/v4 v4.0.0 h1:sRjfPpun/63iADiSvGGjgA1cAYegEWMPCJdUpJYn9JA= +github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= @@ -331,6 +337,7 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/internal/myks/assets/myks_config.yaml b/internal/myks/assets/myks_config.yaml new file mode 100644 index 00000000..78059104 --- /dev/null +++ b/internal/myks/assets/myks_config.yaml @@ -0,0 +1,7 @@ +--- +# Sets the number of applications to be processed in parallel. +# The default (0) is no limit. +async: 0 +# One of the zerolog log levels. +# See: https://github.com/rs/zerolog#leveled-logging +log-level: info diff --git a/internal/myks/globe.go b/internal/myks/globe.go index f590a651..4554941c 100644 --- a/internal/myks/globe.go +++ b/internal/myks/globe.go @@ -22,6 +22,9 @@ var dataSchema []byte //go:embed assets/envs_gitignore var envsGitignore []byte +//go:embed assets/myks_config.yaml +var myksConfig []byte + //go:embed all:assets/prototypes var prototypesFs embed.FS @@ -215,20 +218,49 @@ func (g *Globe) SyncAndRender(asyncLevel int) error { } // Bootstrap creates the initial directory structure and files -func (g *Globe) Bootstrap(force bool) error { - log.Info().Msg("Creating base file structure") - if err := g.createBaseFileStructure(force); err != nil { - return err +func (g *Globe) Bootstrap(force, onlyPrint bool, components []string) error { + compMap := make(map[string]bool, len(components)) + for _, comp := range components { + compMap[comp] = true } - log.Info().Msg("Creating sample prototypes") - if err := g.createSamplePrototypes(); err != nil { - return err + if onlyPrint { + if compMap["gitignore"] { + printFileNicely(".gitignore", string(envsGitignore), "Terminfo") + } + if compMap["config"] { + printFileNicely(".myks.yaml", string(myksConfig), "YAML") + } + if compMap["schema"] { + printFileNicely("data-schema.ytt.yaml", string(dataSchema), "YAML") + } + } else { + log.Info().Msg("Creating base file structure") + if err := g.createBaseFileStructure(force); err != nil { + return err + } } - log.Info().Msg("Creating sample environment") - if err := g.createSampleEnvironment(); err != nil { - return err + if compMap["prototypes"] { + if onlyPrint { + log.Info().Msg("Skipping printing sample prototypes") + } else { + log.Info().Msg("Creating sample prototypes") + if err := g.createSamplePrototypes(); err != nil { + return err + } + } + } + + if compMap["envs"] { + if onlyPrint { + log.Debug().Msg("Skipping printing sample environment") + } else { + log.Info().Msg("Creating sample environment") + if err := g.createSampleEnvironment(); err != nil { + return err + } + } } return nil @@ -270,11 +302,13 @@ func (g *Globe) createBaseFileStructure(force bool) error { protoDir := filepath.Join(g.RootDir, g.PrototypesDir) renderedDir := filepath.Join(g.RootDir, g.RenderedDir) envsGitignoreFile := filepath.Join(envDir, ".gitignore") + myksConfigFile := filepath.Join(g.RootDir, ".myks.yaml") log.Debug().Str("environments directory", envDir).Msg("") log.Debug().Str("prototypes directory", protoDir).Msg("") log.Debug().Str("rendered directory", renderedDir).Msg("") log.Debug().Str("environments .gitignore file", envsGitignoreFile).Msg("") + log.Debug().Str("myks config file", myksConfigFile).Msg("") if !force { if _, err := os.Stat(envDir); err == nil { @@ -289,6 +323,9 @@ func (g *Globe) createBaseFileStructure(force bool) error { if _, err := os.Stat(envsGitignoreFile); err == nil { return ErrNotClean } + if _, err := os.Stat(myksConfigFile); err == nil { + return ErrNotClean + } } g.createDataSchemaFile() @@ -309,6 +346,10 @@ func (g *Globe) createBaseFileStructure(force bool) error { return err } + if err := os.WriteFile(myksConfigFile, myksConfig, 0o600); err != nil { + return err + } + return nil } diff --git a/internal/myks/util.go b/internal/myks/util.go index ac1ddc47..c139d07e 100644 --- a/internal/myks/util.go +++ b/internal/myks/util.go @@ -15,8 +15,11 @@ import ( "regexp" "strings" + "github.com/alecthomas/chroma/quick" + aurora "github.com/logrusorgru/aurora/v4" "github.com/rs/zerolog/log" "golang.org/x/sync/errgroup" + "golang.org/x/term" yaml "gopkg.in/yaml.v3" ) @@ -36,6 +39,21 @@ func reductSecrets(args []string) []string { return logArgs } +func printFileNicely(name, content, syntax string) { + if !term.IsTerminal(int(os.Stdout.Fd())) { + fmt.Println(content) + return + } + + fmt.Println(aurora.Bold(fmt.Sprintf("=== %s ===\n", name))) + err := quick.Highlight(os.Stdout, content, syntax, "terminal16m", "doom-one2") + if err != nil { + log.Error().Err(err).Msg("Failed to highlight") + } else { + fmt.Printf("\n\n") + } +} + func process(asyncLevel int, collection interface{}, fn func(interface{}) error) error { var items []interface{}