This is an automated email from the ASF dual-hosted git repository.

lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 24efaa0f1fd5b9b1489a324b7a512194bd45e041
Author: lburgazzoli <[email protected]>
AuthorDate: Wed Nov 27 18:22:19 2019 +0100

    Allow to configure kamel CLI with env vars and configuration files #1108
---
 go.mod                                |   2 +
 go.sum                                |  11 ++
 pkg/cmd/builder.go                    |  15 ++-
 pkg/cmd/delete.go                     |  17 +--
 pkg/cmd/describe_integration.go       |   3 +-
 pkg/cmd/describe_kit.go               |   7 +-
 pkg/cmd/describe_platform.go          |   7 +-
 pkg/cmd/get.go                        |   9 +-
 pkg/cmd/install.go                    | 237 +++++++++++++++++++---------------
 pkg/cmd/kit_create.go                 |  74 +++++------
 pkg/cmd/kit_delete.go                 |  27 ++--
 pkg/cmd/kit_get.go                    |  25 ++--
 pkg/cmd/log.go                        |  13 +-
 pkg/cmd/operator.go                   |  17 +--
 pkg/cmd/rebuild.go                    |   9 +-
 pkg/cmd/reset.go                      |  21 +--
 pkg/cmd/root.go                       |  35 ++++-
 pkg/cmd/{operator.go => root_test.go} |  27 +---
 pkg/cmd/run.go                        | 102 ++++++++-------
 pkg/cmd/util.go                       | 144 +++++++++++++++++++++
 20 files changed, 495 insertions(+), 307 deletions(-)

diff --git a/go.mod b/go.mod
index 5af83f5..3f5c829 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require (
        github.com/coreos/prometheus-operator v0.29.0
        github.com/evanphx/json-patch v4.5.0+incompatible
        github.com/fatih/structs v1.1.0
+       github.com/gertd/go-pluralize v0.1.1
        github.com/go-logr/logr v0.1.0
        github.com/google/go-containerregistry 
v0.0.0-20190206233756-dbc4da98389f // indirect
        github.com/google/uuid v1.1.1
@@ -23,6 +24,7 @@ require (
        github.com/sirupsen/logrus v1.4.2
        github.com/spf13/cobra v0.0.5
        github.com/spf13/pflag v1.0.3
+       github.com/spf13/viper v1.4.0
        github.com/stoewer/go-strcase v1.0.2
        github.com/stretchr/testify v1.3.0
        go.uber.org/multierr v1.1.0
diff --git a/go.sum b/go.sum
index c55c3c8..c21e98d 100644
--- a/go.sum
+++ b/go.sum
@@ -13,6 +13,7 @@ github.com/Azure/azure-sdk-for-go v21.4.0+incompatible/go.mod 
h1:9XXNKU+eRnpl9mo
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod 
h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
 github.com/Azure/go-autorest v11.1.2+incompatible/go.mod 
h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/BurntSushi/toml v0.3.0/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v0.3.1 
h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 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/DATA-DOG/go-sqlmock v1.3.3/go.mod 
h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
@@ -137,6 +138,8 @@ github.com/fatih/structs v1.1.0 
h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
 github.com/fatih/structs v1.1.0/go.mod 
h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/fsnotify/fsnotify v1.4.7 
h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod 
h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/gertd/go-pluralize v0.1.1 
h1:fQhql/WRRwr4TVp+TCw12s2esCacvEVBdkTUUwNqF/Q=
+github.com/gertd/go-pluralize v0.1.1/go.mod 
h1:t5DfHcumb6m0RqyVJDrDLEzL2AGeaiqUXIcDNwLaeAs=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -276,6 +279,7 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod 
h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
 github.com/hashicorp/golang-lru v0.5.1 
h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
 github.com/hashicorp/golang-lru v0.5.1/go.mod 
h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1/go.mod 
h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod 
h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/heketi/heketi v0.0.0-20181109135656-558b29266ce0/go.mod 
h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o=
 github.com/heketi/rest v0.0.0-20180404230133-aa6a65207413/go.mod 
h1:BeS3M108VzVlmAue3lv2WcGuPAX94/KN63MUURzbYSI=
@@ -335,6 +339,7 @@ github.com/liggitt/tabwriter 
v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9
 github.com/lithammer/dedent v1.1.0/go.mod 
h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
 github.com/lpabon/godbc v0.1.1/go.mod 
h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA=
 github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.0 
h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
 github.com/magiconair/properties v1.8.0/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod 
h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 
h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
@@ -360,6 +365,7 @@ github.com/miekg/dns 
v0.0.0-20160614162101-5d001d020961/go.mod h1:W1PPwlIAgtquWB
 github.com/mindprince/gonvml v0.0.0-20171110221305-fee913ce8fb2/go.mod 
h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY=
 github.com/mistifyio/go-zfs v0.0.0-20151009155749-1b4ae6fb4e77/go.mod 
h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
 github.com/mitchellh/copystructure v1.0.0/go.mod 
h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/go-homedir v1.1.0 
h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod 
h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/mapstructure v1.1.2 
h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
@@ -417,6 +423,7 @@ github.com/operator-framework/operator-sdk v0.12.0 
h1:9eAD1L8e6pPCpFCAacBUVf2elo
 github.com/operator-framework/operator-sdk v0.12.0/go.mod 
h1:mW8isQxiXlLCVf2E+xqflkQAVLOTbiqjndKdkKIrR0M=
 github.com/pborman/uuid v1.2.0/go.mod 
h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.0.1/go.mod 
h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.2.0 
h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
 github.com/pelletier/go-toml v1.2.0/go.mod 
h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod 
h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4=
 github.com/peterbourgon/diskv v2.0.1+incompatible 
h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
@@ -492,14 +499,17 @@ github.com/soheilhy/cmux v0.1.4/go.mod 
h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod 
h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97/go.mod 
h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.1.2/go.mod 
h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
 github.com/spf13/afero v1.2.2/go.mod 
h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a/go.mod 
h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
 github.com/spf13/cast v1.3.0/go.mod 
h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod 
h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.3/go.mod 
h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
 github.com/spf13/cobra v0.0.5/go.mod 
h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
 github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80/go.mod 
h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.0.0 
h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod 
h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -508,6 +518,7 @@ github.com/spf13/pflag v1.0.3 
h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
 github.com/spf13/pflag v1.0.3/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/viper v0.0.0-20160820190039-7fb2782df3d8/go.mod 
h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
 github.com/spf13/viper v1.3.2/go.mod 
h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
 github.com/spf13/viper v1.4.0/go.mod 
h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50/go.mod 
h1:1pdIZTAHUz+HDKDVZ++5xg/duPlhKAIzw9qy42CWYp4=
 github.com/stoewer/go-strcase v1.0.2 
h1:l3iQ2FPu8+36ars/7syO1dQAkjwMCb1IE3J+Th0ohfE=
diff --git a/pkg/cmd/builder.go b/pkg/cmd/builder.go
index adb9509..9517e7d 100644
--- a/pkg/cmd/builder.go
+++ b/pkg/cmd/builder.go
@@ -27,21 +27,22 @@ func newCmdBuilder(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                RootCmdOptions: rootCmdOptions,
        }
        cmd := cobra.Command{
-               Use:    "builder",
-               Short:  "Run the Camel K builder",
-               Long:   `Run the Camel K builder`,
-               Hidden: true,
-               Run:    impl.run,
+               Use:     "builder",
+               Short:   "Run the Camel K builder",
+               Long:    `Run the Camel K builder`,
+               Hidden:  true,
+               PreRunE: decode(&impl),
+               Run:     impl.run,
        }
 
-       cmd.Flags().StringVar(&impl.BuildName, "build-name", "", "The name of 
the build resource")
+       cmd.Flags().String("build-name", "", "The name of the build resource")
 
        return &cmd
 }
 
 type builderCmdOptions struct {
        *RootCmdOptions
-       BuildName string
+       BuildName string `mapstructure:"build-name"`
 }
 
 func (o *builderCmdOptions) run(_ *cobra.Command, _ []string) {
diff --git a/pkg/cmd/delete.go b/pkg/cmd/delete.go
index 6eeda59..a3d9a55 100644
--- a/pkg/cmd/delete.go
+++ b/pkg/cmd/delete.go
@@ -36,8 +36,9 @@ func newCmdDelete(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                RootCmdOptions: rootCmdOptions,
        }
        cmd := cobra.Command{
-               Use:   "delete [integration1] [integration2] ...",
-               Short: "Delete integrations deployed on Kubernetes",
+               Use:     "delete [integration1] [integration2] ...",
+               Short:   "Delete integrations deployed on Kubernetes",
+               PreRunE: decode(&impl),
                RunE: func(_ *cobra.Command, args []string) error {
                        if err := impl.validate(args); err != nil {
                                return err
@@ -50,21 +51,21 @@ func newCmdDelete(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                },
        }
 
-       cmd.Flags().BoolVar(&impl.deleteAll, "all", false, "Delete all 
integrations")
+       cmd.Flags().Bool("all", false, "Delete all integrations")
 
        return &cmd
 }
 
 type deleteCmdOptions struct {
        *RootCmdOptions
-       deleteAll bool
+       DeleteAll bool `mapstructure:"all"`
 }
 
 func (command *deleteCmdOptions) validate(args []string) error {
-       if command.deleteAll && len(args) > 0 {
+       if command.DeleteAll && len(args) > 0 {
                return errors.New("invalid combination: both all flag and named 
integrations are set")
        }
-       if !command.deleteAll && len(args) == 0 {
+       if !command.DeleteAll && len(args) == 0 {
                return errors.New("invalid combination: neither all flag nor 
named integrations are set")
        }
 
@@ -76,7 +77,7 @@ func (command *deleteCmdOptions) run(args []string) error {
        if err != nil {
                return err
        }
-       if len(args) != 0 && !command.deleteAll {
+       if len(args) != 0 && !command.DeleteAll {
                for _, arg := range args {
                        name := kubernetes.SanitizeName(arg)
                        err := DeleteIntegration(command.Context, c, name, 
command.Namespace)
@@ -90,7 +91,7 @@ func (command *deleteCmdOptions) run(args []string) error {
                                fmt.Println("Integration " + name + " deleted")
                        }
                }
-       } else if command.deleteAll {
+       } else if command.DeleteAll {
                integrationList := v1alpha1.IntegrationList{
                        TypeMeta: metav1.TypeMeta{
                                APIVersion: 
v1alpha1.SchemeGroupVersion.String(),
diff --git a/pkg/cmd/describe_integration.go b/pkg/cmd/describe_integration.go
index 117868f..25882f4 100644
--- a/pkg/cmd/describe_integration.go
+++ b/pkg/cmd/describe_integration.go
@@ -41,6 +41,7 @@ func newDescribeIntegrationCmd(rootCmdOptions 
*RootCmdOptions) *cobra.Command {
                Aliases: []string{"it"},
                Short:   "Describe an Integration",
                Long:    `Describe an Integration.`,
+               PreRunE: decode(&impl),
                RunE: func(_ *cobra.Command, args []string) error {
                        if err := impl.validate(args); err != nil {
                                return err
@@ -60,7 +61,7 @@ func newDescribeIntegrationCmd(rootCmdOptions 
*RootCmdOptions) *cobra.Command {
 
 type describeIntegrationCommand struct {
        *RootCmdOptions
-       showSourceContent bool
+       showSourceContent bool `mapstructure:"show-source-content"`
 }
 
 func (command *describeIntegrationCommand) validate(args []string) error {
diff --git a/pkg/cmd/describe_kit.go b/pkg/cmd/describe_kit.go
index c182650..a3ce855 100644
--- a/pkg/cmd/describe_kit.go
+++ b/pkg/cmd/describe_kit.go
@@ -34,9 +34,10 @@ func newDescribeKitCmd(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        }
 
        cmd := cobra.Command{
-               Use:   "kit",
-               Short: "Describe an Integration Kit",
-               Long:  `Describe an Integration Kit.`,
+               Use:     "kit",
+               Short:   "Describe an Integration Kit",
+               Long:    `Describe an Integration Kit.`,
+               PreRunE: decode(impl),
                RunE: func(_ *cobra.Command, args []string) error {
                        if err := impl.validate(args); err != nil {
                                return err
diff --git a/pkg/cmd/describe_platform.go b/pkg/cmd/describe_platform.go
index 162a7a0..17c639b 100644
--- a/pkg/cmd/describe_platform.go
+++ b/pkg/cmd/describe_platform.go
@@ -34,9 +34,10 @@ func newDescribePlatformCmd(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        }
 
        cmd := cobra.Command{
-               Use:   "platform",
-               Short: "Describe an Integration Platform",
-               Long:  `Describe an Integration Platform.`,
+               Use:     "platform",
+               Short:   "Describe an Integration Platform",
+               Long:    `Describe an Integration Platform.`,
+               PreRunE: decode(impl),
                RunE: func(_ *cobra.Command, args []string) error {
                        if err := impl.validate(args); err != nil {
                                return err
diff --git a/pkg/cmd/get.go b/pkg/cmd/get.go
index 6774065..d5dea19 100644
--- a/pkg/cmd/get.go
+++ b/pkg/cmd/get.go
@@ -39,10 +39,11 @@ func newCmdGet(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                RootCmdOptions: rootCmdOptions,
        }
        cmd := cobra.Command{
-               Use:   "get [integration]",
-               Short: "Get integrations deployed on Kubernetes",
-               Long:  `Get the status of integrations deployed on on 
Kubernetes.`,
-               RunE:  options.run,
+               Use:     "get [integration]",
+               Short:   "Get integrations deployed on Kubernetes",
+               Long:    `Get the status of integrations deployed on on 
Kubernetes.`,
+               PreRunE: decode(&options),
+               RunE:    options.run,
        }
 
        return &cmd
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 56f8c33..bc10726 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -38,6 +38,7 @@ import (
 
        "github.com/pkg/errors"
        "github.com/spf13/cobra"
+       "github.com/spf13/viper"
 
        corev1 "k8s.io/api/core/v1"
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -49,45 +50,53 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        }
        cmd := cobra.Command{
                Use:     "install",
-               Short:   "Install Camel K on a Kubernetes cluster",
+               Short:   "Installs Camel K on a Kubernetes cluster",
                Long:    `Installs Camel K on a Kubernetes or OpenShift 
cluster.`,
-               PreRunE: impl.validate,
-               RunE:    impl.install,
+               PreRunE: impl.decode,
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       if err := impl.validate(cmd, args); err != nil {
+                               return err
+                       }
+                       if err := impl.install(cmd, args); err != nil {
+                               return err
+                       }
+                       return nil
+               },
        }
 
-       cmd.Flags().BoolVarP(&impl.wait, "wait", "w", false, "Waits for the 
platform to be running")
-       cmd.Flags().BoolVar(&impl.clusterSetupOnly, "cluster-setup", false, 
"Execute cluster-wide operations only (may require admin rights)")
-       cmd.Flags().StringVar(&impl.clusterType, "cluster-type", "", "Set 
explicitly the cluster type to Kubernetes or OpenShift")
-       cmd.Flags().BoolVar(&impl.skipOperatorSetup, "skip-operator-setup", 
false, "Do not install the operator in the namespace (in case there's a global 
one)")
-       cmd.Flags().BoolVar(&impl.skipClusterSetup, "skip-cluster-setup", 
false, "Skip the cluster-setup phase")
-       cmd.Flags().BoolVar(&impl.exampleSetup, "example", false, "Install 
example integration")
-       cmd.Flags().BoolVar(&impl.global, "global", false, "Configure the 
operator to watch all namespaces. No integration platform is created.")
-
-       cmd.Flags().StringVarP(&impl.outputFormat, "output", "o", "", "Output 
format. One of: json|yaml")
-       cmd.Flags().StringVar(&impl.registry.Organization, "organization", "", 
"A organization on the Docker registry that can be used to publish images")
-       cmd.Flags().StringVar(&impl.registry.Address, "registry", "", "A Docker 
registry that can be used to publish images")
-       cmd.Flags().StringVar(&impl.registry.Secret, "registry-secret", "", "A 
secret used to push/pull images to the Docker registry")
-       cmd.Flags().BoolVar(&impl.registry.Insecure, "registry-insecure", 
false, "Configure to configure registry access in insecure mode or not")
-       cmd.Flags().StringVar(&impl.registryAuth.Server, 
"registry-auth-server", "", "The docker registry authentication server")
-       cmd.Flags().StringVar(&impl.registryAuth.Username, 
"registry-auth-username", "", "The docker registry authentication username")
-       cmd.Flags().StringVar(&impl.registryAuth.Password, 
"registry-auth-password", "", "The docker registry authentication password")
-       cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, 
"Add a camel property")
-       cmd.Flags().StringVar(&impl.camelVersion, "camel-version", "", "Set the 
camel version")
-       cmd.Flags().StringVar(&impl.runtimeVersion, "runtime-version", "", "Set 
the camel-k runtime version")
-       cmd.Flags().StringVar(&impl.baseImage, "base-image", "", "Set the base 
image used to run integrations")
-       cmd.Flags().StringVar(&impl.operatorImage, "operator-image", "", "Set 
the operator image used for the operator deployment")
-       cmd.Flags().StringSliceVar(&impl.kits, "kit", nil, "Add an integration 
kit to build at startup")
-       cmd.Flags().StringVar(&impl.buildStrategy, "build-strategy", "", "Set 
the build strategy")
-       cmd.Flags().StringVar(&impl.buildTimeout, "build-timeout", "", "Set how 
long the build process can last")
-       cmd.Flags().StringVar(&impl.traitProfile, "trait-profile", "", "The 
profile to use for traits")
-       cmd.Flags().BoolVar(&impl.kanikoBuildCache, "kaniko-build-cache", true, 
"To enable or disable the Kaniko Cache in building phase")
-       cmd.Flags().StringVar(&impl.httpProxySecret, "http-proxy-secret", "", 
"Configure the source of the secret holding HTTP proxy server details "+
+       cmd.Flags().BoolP("wait", "w", false, "Waits for the platform to be 
running")
+       cmd.Flags().Bool("cluster-setup", false, "Execute cluster-wide 
operations only (may require admin rights)")
+       cmd.Flags().String("cluster-type", "", "Set explicitly the cluster type 
to Kubernetes or OpenShift")
+       cmd.Flags().Bool("skip-operator-setup", false, "Do not install the 
operator in the namespace (in case there's a global one)")
+       cmd.Flags().Bool("skip-cluster-setup", false, "Skip the cluster-setup 
phase")
+       cmd.Flags().Bool("example", false, "Install example integration")
+       cmd.Flags().Bool("global", false, "Configure the operator to watch all 
namespaces. No integration platform is created.")
+
+       cmd.Flags().StringP("output", "o", "", "Output format. One of: 
json|yaml")
+       cmd.Flags().String("organization", "", "A organization on the Docker 
registry that can be used to publish images")
+       cmd.Flags().String("registry", "", "A Docker registry that can be used 
to publish images")
+       cmd.Flags().String("registry-secret", "", "A secret used to push/pull 
images to the Docker registry")
+       cmd.Flags().Bool("registry-insecure", false, "Configure to configure 
registry access in insecure mode or not")
+       cmd.Flags().String("registry-auth-server", "", "The docker registry 
authentication server")
+       cmd.Flags().String("registry-auth-username", "", "The docker registry 
authentication username")
+       cmd.Flags().String("registry-auth-password", "", "The docker registry 
authentication password")
+       cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property")
+       cmd.Flags().String("camel-version", "", "Set the camel version")
+       cmd.Flags().String("runtime-version", "", "Set the camel-k runtime 
version")
+       cmd.Flags().String("base-image", "", "Set the base Image used to run 
integrations")
+       cmd.Flags().String("operator-image", "", "Set the operator Image used 
for the operator deployment")
+       cmd.Flags().StringArray("kit", nil, "Add an integration kit to build at 
startup")
+       cmd.Flags().String("build-strategy", "", "Set the build strategy")
+       cmd.Flags().String("build-timeout", "", "Set how long the build process 
can last")
+       cmd.Flags().String("trait-profile", "", "The profile to use for traits")
+       cmd.Flags().Bool("kaniko-build-cache", true, "To enable or disable the 
Kaniko Cache in building phase")
+       cmd.Flags().String("http-proxy-secret", "", "Configure the source of 
the secret holding HTTP proxy server details "+
                "(HTTP_PROXY|HTTPS_PROXY|NO_PROXY)")
 
        // maven settings
-       cmd.Flags().StringVar(&impl.localRepository, "local-repository", "", 
"Location of the local maven repository")
-       cmd.Flags().StringVar(&impl.mavenSettings, "maven-settings", "", 
"Configure the source of the maven settings (configmap|secret:name[/key])")
-       cmd.Flags().StringSliceVar(&impl.mavenRepositories, "maven-repository", 
nil, "Add a maven repository")
+       cmd.Flags().String("local-repository", "", "Location of the local maven 
repository")
+       cmd.Flags().String("maven-settings", "", "Configure the source of the 
maven settings (configmap|secret:name[/key])")
+       cmd.Flags().StringArray("maven-repository", nil, "Add a maven 
repository")
 
        // completion support
        configureBashAnnotationForFlag(
@@ -103,40 +112,41 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
 
 type installCmdOptions struct {
        *RootCmdOptions
-       wait              bool
-       clusterSetupOnly  bool
-       skipOperatorSetup bool
-       skipClusterSetup  bool
-       exampleSetup      bool
-       global            bool
-       kanikoBuildCache  bool
-       clusterType       string
-       outputFormat      string
-       camelVersion      string
-       runtimeVersion    string
-       baseImage         string
-       operatorImage     string
-       localRepository   string
-       buildStrategy     string
-       buildTimeout      string
-       mavenRepositories []string
-       mavenSettings     string
-       properties        []string
-       kits              []string
-       registry          v1alpha1.IntegrationPlatformRegistrySpec
-       registryAuth      registry.Auth
-       traitProfile      string
-       httpProxySecret   string
+       Wait              bool     `mapstructure:"wait"`
+       ClusterSetupOnly  bool     `mapstructure:"cluster-setup"`
+       SkipOperatorSetup bool     `mapstructure:"skip-operator-setup"`
+       SkipClusterSetup  bool     `mapstructure:"skip-cluster-setup"`
+       ExampleSetup      bool     `mapstructure:"example"`
+       Global            bool     `mapstructure:"global"`
+       KanikoBuildCache  bool     `mapstructure:"kaniko-build-cache"`
+       ClusterType       string   `mapstructure:"cluster-type"`
+       OutputFormat      string   `mapstructure:"output"`
+       CamelVersion      string   `mapstructure:"camel-version"`
+       RuntimeVersion    string   `mapstructure:"runtime-version"`
+       BaseImage         string   `mapstructure:"base-image"`
+       OperatorImage     string   `mapstructure:"operator-image"`
+       LocalRepository   string   `mapstructure:"local-repository"`
+       BuildStrategy     string   `mapstructure:"build-strategy"`
+       BuildTimeout      string   `mapstructure:"build-timeout"`
+       MavenRepositories []string `mapstructure:"maven-repositories"`
+       MavenSettings     string   `mapstructure:"maven-settings"`
+       Properties        []string `mapstructure:"properties"`
+       Kits              []string `mapstructure:"kits"`
+       TraitProfile      string   `mapstructure:"trait-profile"`
+       HTTPProxySecret   string   `mapstructure:"http-proxy-secret"`
+
+       registry     v1alpha1.IntegrationPlatformRegistrySpec
+       registryAuth registry.Auth
 }
 
 // nolint: gocyclo
-func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error 
{
+func (o *installCmdOptions) install(_ *cobra.Command, _ []string) error {
        var collection *kubernetes.Collection
-       if o.outputFormat != "" {
+       if o.OutputFormat != "" {
                collection = kubernetes.NewCollection()
        }
 
-       if !o.skipClusterSetup {
+       if !o.SkipClusterSetup {
                // Let's use a client provider during cluster installation, to 
eliminate the problem of CRD object caching
                clientProvider := client.Provider{Get: o.NewCmdClient}
 
@@ -151,7 +161,7 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
                }
        }
 
-       if o.clusterSetupOnly {
+       if o.ClusterSetupOnly {
                if collection == nil {
                        fmt.Println("Camel K cluster setup completed 
successfully")
                }
@@ -163,12 +173,12 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
 
                namespace := o.Namespace
 
-               if !o.skipOperatorSetup {
+               if !o.SkipOperatorSetup {
                        cfg := install.OperatorConfiguration{
-                               CustomImage: o.operatorImage,
+                               CustomImage: o.OperatorImage,
                                Namespace:   namespace,
-                               Global:      o.global,
-                               ClusterType: o.clusterType,
+                               Global:      o.Global,
+                               ClusterType: o.ClusterType,
                        }
                        err = install.OperatorOrCollect(o.Context, c, cfg, 
collection)
                        if err != nil {
@@ -188,7 +198,7 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
                        }
                }
 
-               platform, err := install.PlatformOrCollect(o.Context, c, 
o.clusterType, namespace, o.registry, collection)
+               platform, err := install.PlatformOrCollect(o.Context, c, 
o.ClusterType, namespace, o.registry, collection)
                if err != nil {
                        return err
                }
@@ -197,10 +207,10 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
                        platform.Spec.Build.Registry.Secret = 
generatedSecretName
                }
 
-               if len(o.properties) > 0 {
+               if len(o.Properties) > 0 {
                        platform.Spec.Build.Properties = make(map[string]string)
 
-                       for _, property := range o.properties {
+                       for _, property := range o.Properties {
                                kv := strings.Split(property, "=")
 
                                if len(kv) == 2 {
@@ -208,20 +218,20 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
                                }
                        }
                }
-               if o.localRepository != "" {
-                       platform.Spec.Build.Maven.LocalRepository = 
o.localRepository
+               if o.LocalRepository != "" {
+                       platform.Spec.Build.Maven.LocalRepository = 
o.LocalRepository
                }
-               if o.camelVersion != "" {
-                       platform.Spec.Build.CamelVersion = o.camelVersion
+               if o.CamelVersion != "" {
+                       platform.Spec.Build.CamelVersion = o.CamelVersion
                }
-               if o.runtimeVersion != "" {
-                       platform.Spec.Build.RuntimeVersion = o.runtimeVersion
+               if o.RuntimeVersion != "" {
+                       platform.Spec.Build.RuntimeVersion = o.RuntimeVersion
                }
-               if o.baseImage != "" {
-                       platform.Spec.Build.BaseImage = o.baseImage
+               if o.BaseImage != "" {
+                       platform.Spec.Build.BaseImage = o.BaseImage
                }
-               if o.buildStrategy != "" {
-                       switch s := o.buildStrategy; s {
+               if o.BuildStrategy != "" {
+                       switch s := o.BuildStrategy; s {
                        case v1alpha1.IntegrationPlatformBuildStrategyPod:
                                platform.Spec.Build.BuildStrategy = 
v1alpha1.IntegrationPlatformBuildStrategyPod
                        case v1alpha1.IntegrationPlatformBuildStrategyRoutine:
@@ -230,8 +240,8 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
                                return fmt.Errorf("unknown build strategy: %s", 
s)
                        }
                }
-               if o.buildTimeout != "" {
-                       d, err := time.ParseDuration(o.buildTimeout)
+               if o.BuildTimeout != "" {
+                       d, err := time.ParseDuration(o.BuildTimeout)
                        if err != nil {
                                return err
                        }
@@ -240,54 +250,52 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
                                Duration: d,
                        }
                }
-               if o.traitProfile != "" {
-                       platform.Spec.Profile = 
v1alpha1.TraitProfileByName(o.traitProfile)
+               if o.TraitProfile != "" {
+                       platform.Spec.Profile = 
v1alpha1.TraitProfileByName(o.TraitProfile)
                }
 
-               if len(o.mavenRepositories) > 0 {
-                       for _, r := range o.mavenRepositories {
+               if len(o.MavenRepositories) > 0 {
+                       for _, r := range o.MavenRepositories {
                                platform.AddConfiguration("repository", r)
                        }
                }
 
-               if o.mavenSettings != "" {
-                       mavenSettings, err := 
decodeMavenSettings(o.mavenSettings)
+               if o.MavenSettings != "" {
+                       mavenSettings, err := 
decodeMavenSettings(o.MavenSettings)
                        if err != nil {
                                return err
                        }
                        platform.Spec.Build.Maven.Settings = mavenSettings
                }
 
-               if o.httpProxySecret != "" {
-                       platform.Spec.Build.HTTPProxySecret = o.httpProxySecret
+               if o.HTTPProxySecret != "" {
+                       platform.Spec.Build.HTTPProxySecret = o.HTTPProxySecret
                }
 
-               if o.clusterType != "" {
+               if o.ClusterType != "" {
                        for _, c := range 
v1alpha1.AllIntegrationPlatformClusters {
-                               if strings.EqualFold(string(c), o.clusterType) {
+                               if strings.EqualFold(string(c), o.ClusterType) {
                                        platform.Spec.Cluster = c
                                }
                        }
                }
 
-               kanikoBuildCacheFlag := 
cobraCmd.Flags().Lookup("kaniko-build-cache")
-
-               if kanikoBuildCacheFlag.Changed {
-                       platform.Spec.Build.KanikoBuildCache = 
&o.kanikoBuildCache
+               if !o.KanikoBuildCache {
+                       platform.Spec.Build.KanikoBuildCache = 
&o.KanikoBuildCache
                }
 
-               platform.Spec.Resources.Kits = o.kits
+               platform.Spec.Resources.Kits = o.Kits
 
                // Do not create an integration platform in global mode as 
platforms are expected
                // to be created in other namespaces
-               if !o.global {
+               if !o.Global {
                        err = install.RuntimeObjectOrCollect(o.Context, c, 
namespace, collection, platform)
                        if err != nil {
                                return err
                        }
                }
 
-               if o.exampleSetup {
+               if o.ExampleSetup {
                        err = install.ExampleOrCollect(o.Context, c, namespace, 
collection)
                        if err != nil {
                                return err
@@ -295,14 +303,14 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
                }
 
                if collection == nil {
-                       if o.wait {
+                       if o.Wait {
                                err = o.waitForPlatformReady(platform)
                                if err != nil {
                                        return err
                                }
                        }
 
-                       if o.global {
+                       if o.Global {
                                fmt.Println("Camel K installed in namespace", 
namespace, "(global mode)")
                        } else {
                                fmt.Println("Camel K installed in namespace", 
namespace)
@@ -319,7 +327,7 @@ func (o *installCmdOptions) install(cobraCmd 
*cobra.Command, _ []string) error {
 
 func (o *installCmdOptions) printOutput(collection *kubernetes.Collection) 
error {
        lst := collection.AsKubernetesList()
-       switch o.outputFormat {
+       switch o.OutputFormat {
        case "yaml":
                data, err := kubernetes.ToYAML(lst)
                if err != nil {
@@ -333,7 +341,7 @@ func (o *installCmdOptions) printOutput(collection 
*kubernetes.Collection) error
                }
                fmt.Print(string(data))
        default:
-               return errors.New("unknown output format: " + o.outputFormat)
+               return errors.New("unknown output format: " + o.OutputFormat)
        }
        return nil
 }
@@ -360,6 +368,23 @@ func (o *installCmdOptions) waitForPlatformReady(platform 
*v1alpha1.IntegrationP
        return watch.HandlePlatformStateChanges(o.Context, platform, handler)
 }
 
+func (o *installCmdOptions) decode(cmd *cobra.Command, _ []string) error {
+       path := pathToRoot(cmd)
+       if err := decodeKey(o, path); err != nil {
+               return err
+       }
+
+       o.registry.Address = viper.GetString(path + ".registry")
+       o.registry.Organization = viper.GetString(path + ".organization")
+       o.registry.Secret = viper.GetString(path + ".registry-secret")
+       o.registry.Insecure = viper.GetBool(path + ".registry-insecure")
+       o.registryAuth.Username = viper.GetString(path + 
".registry-auth-username")
+       o.registryAuth.Password = viper.GetString(path + 
".registry-auth-password")
+       o.registryAuth.Server = viper.GetString(path + ".registry-auth-server")
+
+       return nil
+}
+
 func (o *installCmdOptions) validate(_ *cobra.Command, _ []string) error {
        var result error
 
@@ -369,20 +394,20 @@ func (o *installCmdOptions) validate(_ *cobra.Command, _ 
[]string) error {
                return err
        }
 
-       for _, kit := range o.kits {
+       for _, kit := range o.Kits {
                err := errorIfKitIsNotAvailable(schema, kit)
                result = multierr.Append(result, err)
        }
 
-       if len(o.mavenRepositories) > 0 && o.mavenSettings != "" {
+       if len(o.MavenRepositories) > 0 && o.MavenSettings != "" {
                err := fmt.Errorf("incompatible options combinations: you 
cannot set both mavenRepository and mavenSettings")
                result = multierr.Append(result, err)
        }
 
-       if o.traitProfile != "" {
-               tp := v1alpha1.TraitProfileByName(o.traitProfile)
+       if o.TraitProfile != "" {
+               tp := v1alpha1.TraitProfileByName(o.TraitProfile)
                if tp == v1alpha1.TraitProfile("") {
-                       err := fmt.Errorf("unknown trait profile %s", 
o.traitProfile)
+                       err := fmt.Errorf("unknown trait profile %s", 
o.TraitProfile)
                        result = multierr.Append(result, err)
                }
        }
diff --git a/pkg/cmd/kit_create.go b/pkg/cmd/kit_create.go
index f9475ef..3f66c2f 100644
--- a/pkg/cmd/kit_create.go
+++ b/pkg/cmd/kit_create.go
@@ -22,14 +22,13 @@ import (
        "fmt"
        "strings"
 
+       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        "github.com/apache/camel-k/pkg/trait"
-
        "github.com/apache/camel-k/pkg/util"
-
-       "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        "github.com/apache/camel-k/pkg/util/kubernetes"
 
        "github.com/spf13/cobra"
+
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
        k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
@@ -40,20 +39,21 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        }
 
        cmd := cobra.Command{
-               Use:   "create <name>",
-               Short: "Create an Integration Kit",
-               Long:  `Create an Integration Kit.`,
-               Args:  impl.validateArgs,
-               RunE:  impl.run,
-       }
-
-       cmd.Flags().StringVar(&impl.image, "image", "", "Image used to create 
the kit")
-       cmd.Flags().StringSliceVarP(&impl.dependencies, "dependency", "d", nil, 
"Add a dependency")
-       cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, 
"Add a camel property")
-       cmd.Flags().StringSliceVar(&impl.configmaps, "configmap", nil, "Add a 
ConfigMap")
-       cmd.Flags().StringSliceVar(&impl.secrets, "secret", nil, "Add a Secret")
-       cmd.Flags().StringSliceVar(&impl.repositories, "repository", nil, "Add 
a maven repository")
-       cmd.Flags().StringSliceVarP(&impl.traits, "trait", "t", nil, "Configure 
a trait. E.g. \"-t service.enabled=false\"")
+               Use:     "create <name>",
+               Short:   "Create an Integration Kit",
+               Long:    `Create an Integration Kit.`,
+               Args:    impl.validateArgs,
+               PreRunE: decode(impl),
+               RunE:    impl.run,
+       }
+
+       cmd.Flags().String("image", "", "Image used to create the kit")
+       cmd.Flags().StringArrayP("dependency", "d", nil, "Add a dependency")
+       cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property")
+       cmd.Flags().StringArray("configmap", nil, "Add a ConfigMap")
+       cmd.Flags().StringArray("secret", nil, "Add a Secret")
+       cmd.Flags().StringArray("repository", nil, "Add a maven repository")
+       cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. 
\"-t service.enabled=false\"")
 
        // completion support
        configureKnownCompletions(&cmd)
@@ -64,13 +64,13 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
 type kitCreateCommand struct {
        *RootCmdOptions
 
-       image        string
-       dependencies []string
-       properties   []string
-       configmaps   []string
-       secrets      []string
-       repositories []string
-       traits       []string
+       Image        string   `mapstructure:"image"`
+       Dependencies []string `mapstructure:"dependencies"`
+       Properties   []string `mapstructure:"properties"`
+       Configmaps   []string `mapstructure:"configmaps"`
+       Secrets      []string `mapstructure:"secrets"`
+       Repositories []string `mapstructure:"repositories"`
+       Traits       []string `mapstructure:"traits"`
 }
 
 func (command *kitCreateCommand) validateArgs(_ *cobra.Command, args []string) 
error {
@@ -89,7 +89,7 @@ func (command *kitCreateCommand) run(_ *cobra.Command, args 
[]string) error {
 
        catalog := trait.NewCatalog(command.Context, c)
        tp := catalog.ComputeTraitsProperties()
-       for _, t := range command.traits {
+       for _, t := range command.Traits {
                kv := strings.SplitN(t, "=", 2)
 
                if !util.StringSliceExists(tp, kv[0]) {
@@ -118,25 +118,25 @@ func (command *kitCreateCommand) run(_ *cobra.Command, 
args []string) error {
                "camel.apache.org/kit.type": v1alpha1.IntegrationKitTypeUser,
        }
        ctx.Spec = v1alpha1.IntegrationKitSpec{
-               Dependencies:  make([]string, 0, len(command.dependencies)),
+               Dependencies:  make([]string, 0, len(command.Dependencies)),
                Configuration: make([]v1alpha1.ConfigurationSpec, 0),
-               Repositories:  command.repositories,
+               Repositories:  command.Repositories,
        }
 
-       if command.image != "" {
+       if command.Image != "" {
                //
-               // if the image is set, the kit do not require any build but
+               // if the Image is set, the kit do not require any build but
                // is be marked as external as the information about the 
classpath
-               // is missing so it cannot be used as base for other kits
+               // is missing so it cannot be used as base for other Kits
                //
                ctx.Labels["camel.apache.org/kit.type"] = 
v1alpha1.IntegrationKitTypeExternal
 
                //
-               // Set the image to be used by the kit
+               // Set the Image to be used by the kit
                //
-               ctx.Spec.Image = command.image
+               ctx.Spec.Image = command.Image
        }
-       for _, item := range command.dependencies {
+       for _, item := range command.Dependencies {
                switch {
                case strings.HasPrefix(item, "mvn:"):
                        ctx.Spec.Dependencies = append(ctx.Spec.Dependencies, 
item)
@@ -149,25 +149,25 @@ func (command *kitCreateCommand) run(_ *cobra.Command, 
args []string) error {
                }
        }
 
-       for _, item := range command.properties {
+       for _, item := range command.Properties {
                ctx.Spec.Configuration = append(ctx.Spec.Configuration, 
v1alpha1.ConfigurationSpec{
                        Type:  "property",
                        Value: item,
                })
        }
-       for _, item := range command.configmaps {
+       for _, item := range command.Configmaps {
                ctx.Spec.Configuration = append(ctx.Spec.Configuration, 
v1alpha1.ConfigurationSpec{
                        Type:  "configmap",
                        Value: item,
                })
        }
-       for _, item := range command.secrets {
+       for _, item := range command.Secrets {
                ctx.Spec.Configuration = append(ctx.Spec.Configuration, 
v1alpha1.ConfigurationSpec{
                        Type:  "secret",
                        Value: item,
                })
        }
-       for _, item := range command.traits {
+       for _, item := range command.Traits {
                if err := command.configureTrait(&ctx, item); err != nil {
                        return nil
                }
diff --git a/pkg/cmd/kit_delete.go b/pkg/cmd/kit_delete.go
index 0d24172..7902fae 100644
--- a/pkg/cmd/kit_delete.go
+++ b/pkg/cmd/kit_delete.go
@@ -35,9 +35,10 @@ func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        }
 
        cmd := cobra.Command{
-               Use:   "delete",
-               Short: "Delete an Integration Kit",
-               Long:  `Delete an Integration Kit.`,
+               Use:     "delete",
+               Short:   "Delete an Integration Kit",
+               Long:    `Delete an Integration Kit.`,
+               PreRunE: decode(&impl),
                RunE: func(_ *cobra.Command, args []string) error {
                        if err := impl.validate(args); err != nil {
                                return err
@@ -50,22 +51,22 @@ func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                },
        }
 
-       cmd.Flags().BoolVar(&impl.all, "all", false, "Delete all integration 
kits")
+       cmd.Flags().Bool("all", false, "Delete all integration Kits")
 
        return &cmd
 }
 
 type kitDeleteCommand struct {
        *RootCmdOptions
-       all bool
+       All bool `mapstructure:"all"`
 }
 
 func (command *kitDeleteCommand) validate(args []string) error {
-       if command.all && len(args) > 0 {
-               return errors.New("invalid combination: both all flag and named 
kits are set")
+       if command.All && len(args) > 0 {
+               return errors.New("invalid combination: both all flag and named 
Kits are set")
        }
-       if !command.all && len(args) == 0 {
-               return errors.New("invalid combination: neither all flag nor 
named kits are set")
+       if !command.All && len(args) == 0 {
+               return errors.New("invalid combination: neither all flag nor 
named Kits are set")
        }
 
        return nil
@@ -79,7 +80,7 @@ func (command *kitDeleteCommand) run(args []string) error {
                return err
        }
 
-       if command.all {
+       if command.All {
                kitList := v1alpha1.NewIntegrationKitList()
                if err := c.List(command.Context, &kitList, 
k8sclient.InNamespace(command.Namespace)); err != nil {
                        return err
@@ -87,7 +88,7 @@ func (command *kitDeleteCommand) run(args []string) error {
 
                names = make([]string, 0, len(kitList.Items))
                for _, item := range kitList.Items {
-                       // only include non platform kits
+                       // only include non platform Kits
                        if item.Labels["camel.apache.org/kit.type"] != 
v1alpha1.IntegrationKitTypePlatform {
                                names = append(names, item.Name)
                        }
@@ -129,8 +130,8 @@ func (command *kitDeleteCommand) delete(name string) error {
        // check that it is not a platform one which is supposed to be "read 
only"
        // thus not managed by the end user
        if ctx.Labels["camel.apache.org/kit.type"] == 
v1alpha1.IntegrationKitTypePlatform {
-               // skip platform kits while deleting all kits
-               if command.all {
+               // skip platform Kits while deleting all Kits
+               if command.All {
                        return nil
                }
 
diff --git a/pkg/cmd/kit_get.go b/pkg/cmd/kit_get.go
index 9d7f109..a22af7b 100644
--- a/pkg/cmd/kit_get.go
+++ b/pkg/cmd/kit_get.go
@@ -34,9 +34,10 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        }
 
        cmd := cobra.Command{
-               Use:   "get",
-               Short: "Get defined Integration Kit",
-               Long:  `Get defined Integration Kit.`,
+               Use:     "get",
+               Short:   "Get defined Integration Kit",
+               Long:    `Get defined Integration Kit.`,
+               PreRunE: decode(&impl),
                RunE: func(cmd *cobra.Command, args []string) error {
                        if err := impl.validate(cmd, args); err != nil {
                                return err
@@ -49,18 +50,18 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                },
        }
 
-       cmd.Flags().BoolVar(&impl.user, v1alpha1.IntegrationKitTypeUser, true, 
"Includes user kits")
-       cmd.Flags().BoolVar(&impl.external, 
v1alpha1.IntegrationKitTypeExternal, true, "Includes external kits")
-       cmd.Flags().BoolVar(&impl.platform, 
v1alpha1.IntegrationKitTypePlatform, true, "Includes platform kits")
+       cmd.Flags().Bool(v1alpha1.IntegrationKitTypeUser, true, "Includes user 
Kits")
+       cmd.Flags().Bool(v1alpha1.IntegrationKitTypeExternal, true, "Includes 
external Kits")
+       cmd.Flags().Bool(v1alpha1.IntegrationKitTypePlatform, true, "Includes 
platform Kits")
 
        return &cmd
 }
 
 type kitGetCommand struct {
        *RootCmdOptions
-       user     bool
-       external bool
-       platform bool
+       User     bool `mapstructure:"user"`
+       External bool `mapstructure:"external"`
+       Platform bool `mapstructure:"platform"`
 }
 
 func (command *kitGetCommand) validate(cmd *cobra.Command, args []string) 
error {
@@ -81,9 +82,9 @@ func (command *kitGetCommand) run(cmd *cobra.Command) error {
        fmt.Fprintln(w, "NAME\tPHASE\tTYPE\tIMAGE")
        for _, ctx := range kitList.Items {
                t := ctx.Labels["camel.apache.org/kit.type"]
-               u := command.user && t == v1alpha1.IntegrationKitTypeUser
-               e := command.external && t == 
v1alpha1.IntegrationKitTypeExternal
-               p := command.platform && t == 
v1alpha1.IntegrationKitTypePlatform
+               u := command.User && t == v1alpha1.IntegrationKitTypeUser
+               e := command.External && t == 
v1alpha1.IntegrationKitTypeExternal
+               p := command.Platform && t == 
v1alpha1.IntegrationKitTypePlatform
 
                if u || e || p {
                        fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", ctx.Name, 
string(ctx.Status.Phase), t, ctx.Status.Image)
diff --git a/pkg/cmd/log.go b/pkg/cmd/log.go
index 151c8aa..852c9c3 100644
--- a/pkg/cmd/log.go
+++ b/pkg/cmd/log.go
@@ -33,11 +33,12 @@ func newCmdLog(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        }
 
        cmd := cobra.Command{
-               Use:   "log integration",
-               Short: "Print the logs of an integration",
-               Long:  `Print the logs of an integration.`,
-               Args:  options.validate,
-               RunE:  options.run,
+               Use:     "log integration",
+               Short:   "Print the logs of an integration",
+               Long:    `Print the logs of an integration.`,
+               Args:    options.validate,
+               PreRunE: decode(&options),
+               RunE:    options.run,
        }
 
        // completion support
@@ -85,7 +86,7 @@ func (o *logCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
                return err
        }
 
-       // Let's add a wait point, otherwise the script terminates
+       // Let's add a Wait point, otherwise the script terminates
        <-o.Context.Done()
 
        return nil
diff --git a/pkg/cmd/operator.go b/pkg/cmd/operator.go
index a1a70c2..87361fd 100644
--- a/pkg/cmd/operator.go
+++ b/pkg/cmd/operator.go
@@ -22,25 +22,16 @@ import (
        "github.com/spf13/cobra"
 )
 
-func newCmdOperator(rootCmdOptions *RootCmdOptions) *cobra.Command {
-       impl := operatorCmdOptions{
-               RootCmdOptions: rootCmdOptions,
-       }
+func newCmdOperator() *cobra.Command {
        cmd := cobra.Command{
                Use:    "operator",
                Short:  "Run the Camel K operator",
                Long:   `Run the Camel K operator`,
                Hidden: true,
-               Run:    impl.run,
+               Run: func(cmd *cobra.Command, args []string) {
+                       operator.Run()
+               },
        }
 
        return &cmd
 }
-
-type operatorCmdOptions struct {
-       *RootCmdOptions
-}
-
-func (o *operatorCmdOptions) run(_ *cobra.Command, _ []string) {
-       operator.Run()
-}
diff --git a/pkg/cmd/rebuild.go b/pkg/cmd/rebuild.go
index c906b90..d88738a 100644
--- a/pkg/cmd/rebuild.go
+++ b/pkg/cmd/rebuild.go
@@ -34,10 +34,11 @@ func newCmdRebuild(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                RootCmdOptions: rootCmdOptions,
        }
        cmd := cobra.Command{
-               Use:   "rebuild [integration]",
-               Short: "Clear the state of integrations to rebuild them",
-               Long:  `Clear the state of one or more integrations causing a 
rebuild.`,
-               RunE:  options.rebuild,
+               Use:     "rebuild [integration]",
+               Short:   "Clear the state of integrations to rebuild them",
+               Long:    `Clear the state of one or more integrations causing a 
rebuild.`,
+               PreRunE: decode(&options),
+               RunE:    options.rebuild,
        }
 
        return &cmd
diff --git a/pkg/cmd/reset.go b/pkg/cmd/reset.go
index ff9c86d..02bd058 100644
--- a/pkg/cmd/reset.go
+++ b/pkg/cmd/reset.go
@@ -34,22 +34,23 @@ func newCmdReset(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
                RootCmdOptions: rootCmdOptions,
        }
        cmd := cobra.Command{
-               Use:   "reset",
-               Short: "Reset the Camel K installation",
-               Long:  `Reset the Camel K installation by deleting everything 
except current platform configuration.`,
-               Run:   options.reset,
+               Use:     "reset",
+               Short:   "Reset the Camel K installation",
+               Long:    `Reset the Camel K installation by deleting everything 
except current platform configuration.`,
+               PreRunE: decode(&options),
+               Run:     options.reset,
        }
 
-       cmd.Flags().BoolVar(&options.SkipKits, "skip-kits", false, "Do not 
delete the integration kits")
-       cmd.Flags().BoolVar(&options.SkipIntegrations, "skip-integrations", 
false, "Do not delete the integrations")
+       cmd.Flags().Bool("skip-kits", false, "Do not delete the integration 
kits")
+       cmd.Flags().Bool("skip-integrations", false, "Do not delete the 
integrations")
 
        return &cmd
 }
 
 type resetCmdOptions struct {
        *RootCmdOptions
-       SkipKits         bool
-       SkipIntegrations bool
+       SkipKits         bool `mapstructure:"skip-kits"`
+       SkipIntegrations bool `mapstructure:"skip-integrations"`
 }
 
 func (o *resetCmdOptions) reset(_ *cobra.Command, _ []string) {
@@ -73,7 +74,7 @@ func (o *resetCmdOptions) reset(_ *cobra.Command, _ []string) 
{
                        fmt.Print(err)
                        return
                }
-               fmt.Printf("%d integration kits deleted from namespace %s\n", 
n, o.Namespace)
+               fmt.Printf("%d integration Kits deleted from namespace %s\n", 
n, o.Namespace)
        }
 
        if err = o.resetIntegrationPlatform(c); err != nil {
@@ -101,7 +102,7 @@ func (o *resetCmdOptions) deleteAllIntegrations(c 
client.Client) (int, error) {
 func (o *resetCmdOptions) deleteAllIntegrationKits(c client.Client) (int, 
error) {
        list := v1alpha1.NewIntegrationKitList()
        if err := c.List(o.Context, &list, k8sclient.InNamespace(o.Namespace)); 
err != nil {
-               return 0, errors.Wrap(err, fmt.Sprintf("could not retrieve 
integration kits from namespace %s", o.Namespace))
+               return 0, errors.Wrap(err, fmt.Sprintf("could not retrieve 
integration Kits from namespace %s", o.Namespace))
        }
        for _, i := range list.Items {
                kit := i
diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index c5b9168..bbf7acc 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -20,6 +20,9 @@ package cmd
 import (
        "context"
        "os"
+       "strings"
+
+       "github.com/spf13/viper"
 
        "github.com/apache/camel-k/pkg/client"
        "github.com/pkg/errors"
@@ -32,10 +35,10 @@ superpowers.
 
 // RootCmdOptions --
 type RootCmdOptions struct {
-       Context    context.Context
-       _client    client.Client
-       KubeConfig string
-       Namespace  string
+       Context    context.Context `mapstructure:"-"`
+       _client    client.Client   `mapstructure:"-"`
+       KubeConfig string          `mapstructure:"kube-config"`
+       Namespace  string          `mapstructure:"namespace"`
 }
 
 // NewKamelCommand --
@@ -65,9 +68,31 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, 
error) {
        cmd.AddCommand(newCmdReset(&options))
        cmd.AddCommand(newCmdDescribe(&options))
        cmd.AddCommand(newCmdRebuild(&options))
-       cmd.AddCommand(newCmdOperator(&options))
+       cmd.AddCommand(newCmdOperator())
        cmd.AddCommand(newCmdBuilder(&options))
 
+       bindPFlagsHierarchy(&cmd)
+
+       configName := os.Getenv("KAMEL_CONFIG_NAME")
+       if configName != "" {
+               configName = "config"
+       }
+
+       viper.SetConfigName(configName)
+       viper.AddConfigPath(".kamel")
+       viper.AddConfigPath("$HOME/.kamel")
+       viper.AutomaticEnv()
+       viper.SetEnvKeyReplacer(strings.NewReplacer(
+               ".", "_",
+               "-", "_",
+       ))
+
+       if err := viper.ReadInConfig(); err != nil {
+               if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
+                       return nil, err
+               }
+       }
+
        return &cmd, nil
 }
 
diff --git a/pkg/cmd/operator.go b/pkg/cmd/root_test.go
similarity index 59%
copy from pkg/cmd/operator.go
copy to pkg/cmd/root_test.go
index a1a70c2..57f6621 100644
--- a/pkg/cmd/operator.go
+++ b/pkg/cmd/root_test.go
@@ -17,30 +17,7 @@ limitations under the License.
 
 package cmd
 
-import (
-       "github.com/apache/camel-k/pkg/cmd/operator"
-       "github.com/spf13/cobra"
-)
+import "testing"
 
-func newCmdOperator(rootCmdOptions *RootCmdOptions) *cobra.Command {
-       impl := operatorCmdOptions{
-               RootCmdOptions: rootCmdOptions,
-       }
-       cmd := cobra.Command{
-               Use:    "operator",
-               Short:  "Run the Camel K operator",
-               Long:   `Run the Camel K operator`,
-               Hidden: true,
-               Run:    impl.run,
-       }
-
-       return &cmd
-}
-
-type operatorCmdOptions struct {
-       *RootCmdOptions
-}
-
-func (o *operatorCmdOptions) run(_ *cobra.Command, _ []string) {
-       operator.Run()
+func TestDecodeRoot(t *testing.T) {
 }
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 31b411c..4c41081 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -40,8 +40,10 @@ import (
        k8slog "github.com/apache/camel-k/pkg/util/kubernetes/log"
        "github.com/apache/camel-k/pkg/util/sync"
        "github.com/apache/camel-k/pkg/util/watch"
+
        "github.com/pkg/errors"
        "github.com/spf13/cobra"
+
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -57,34 +59,34 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        }
 
        cmd := cobra.Command{
-               Use:   "run [file to run]",
-               Short: "Run a integration on Kubernetes",
-               Long:  `Deploys and execute a integration pod on Kubernetes.`,
-               Args:  options.validateArgs,
-               RunE:  options.run,
-       }
-
-       cmd.Flags().StringVar(&options.IntegrationName, "name", "", "The 
integration name")
-       cmd.Flags().StringSliceVarP(&options.Dependencies, "dependency", "d", 
nil, "The integration dependency")
-       cmd.Flags().BoolVarP(&options.Wait, "wait", "w", false, "Waits for the 
integration to be running")
-       cmd.Flags().StringVarP(&options.IntegrationKit, "kit", "k", "", "The 
kit used to run the integration")
-       cmd.Flags().StringArrayVarP(&options.Properties, "property", "p", nil, 
"Add a camel property")
-       cmd.Flags().StringSliceVar(&options.ConfigMaps, "configmap", nil, "Add 
a ConfigMap")
-       cmd.Flags().StringSliceVar(&options.Secrets, "secret", nil, "Add a 
Secret")
-       cmd.Flags().StringSliceVar(&options.Repositories, "repository", nil, 
"Add a maven repository")
-       cmd.Flags().BoolVar(&options.Logs, "logs", false, "Print integration 
logs")
-       cmd.Flags().BoolVar(&options.Sync, "sync", false, "Synchronize the 
local source file with the cluster, republishing at each change")
-       cmd.Flags().BoolVar(&options.Dev, "dev", false, "Enable Dev mode 
(equivalent to \"-w --logs --sync\")")
-       cmd.Flags().StringVar(&options.Profile, "profile", "", "Trait profile 
used for deployment")
-       cmd.Flags().StringSliceVarP(&options.Traits, "trait", "t", nil, 
"Configure a trait. E.g. \"-t service.enabled=false\"")
-       cmd.Flags().StringSliceVar(&options.LoggingLevels, "logging-level", 
nil, "Configure the logging level. "+
-               "E.g. \"--logging-level org.apache.camel=DEBUG\"")
-       cmd.Flags().StringVarP(&options.OutputFormat, "output", "o", "", 
"Output format. One of: json|yaml")
-       cmd.Flags().BoolVar(&options.Compression, "compression", false, "Enable 
store source as a compressed binary blob")
-       cmd.Flags().StringSliceVar(&options.Resources, "resource", nil, "Add a 
resource")
-       cmd.Flags().StringSliceVar(&options.OpenAPIs, "open-api", nil, "Add an 
OpenAPI v2 spec")
-       cmd.Flags().StringSliceVarP(&options.Volumes, "volume", "v", nil, 
"Mount a volume into the integration container. E.g \"-v 
pvcname:/container/path\"")
-       cmd.Flags().StringSliceVarP(&options.EnvVars, "env", "e", nil, "Set an 
environment variable in the integration container. E.g \"-e MY_VAR=my-value\"")
+               Use:     "run [file to run]",
+               Short:   "Run a integration on Kubernetes",
+               Long:    `Deploys and execute a integration pod on Kubernetes.`,
+               Args:    options.validateArgs,
+               PreRunE: decode(&options),
+               RunE:    options.run,
+       }
+
+       cmd.Flags().String("name", "", "The integration name")
+       cmd.Flags().StringArrayP("dependency", "d", nil, "The integration 
dependency")
+       cmd.Flags().BoolP("wait", "w", false, "Waits for the integration to be 
running")
+       cmd.Flags().StringP("kit", "k", "", "The kit used to run the 
integration")
+       cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property")
+       cmd.Flags().StringArray("configmap", nil, "Add a ConfigMap")
+       cmd.Flags().StringArray("secret", nil, "Add a Secret")
+       cmd.Flags().StringArray("maven-repository", nil, "Add a maven 
repository")
+       cmd.Flags().Bool("logs", false, "Print integration logs")
+       cmd.Flags().Bool("sync", false, "Synchronize the local source file with 
the cluster, republishing at each change")
+       cmd.Flags().Bool("dev", false, "Enable Dev mode (equivalent to \"-w 
--logs --sync\")")
+       cmd.Flags().String("profile", "", "Trait profile used for deployment")
+       cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. 
\"-t service.enabled=false\"")
+       cmd.Flags().StringArray("logging-level", nil, "Configure the logging 
level. e.g. \"--logging-level org.apache.camel=DEBUG\"")
+       cmd.Flags().StringP("output", "o", "", "Output format. One of: 
json|yaml")
+       cmd.Flags().Bool("compression", false, "Enable store source as a 
compressed binary blob")
+       cmd.Flags().StringArray("resource", nil, "Add a resource")
+       cmd.Flags().StringArray("open-api", nil, "Add an OpenAPI v2 spec")
+       cmd.Flags().StringArrayP("volume", "v", nil, "Mount a volume into the 
integration container. E.g \"-v pvcname:/container/path\"")
+       cmd.Flags().StringArrayP("env", "e", nil, "Set an environment variable 
in the integration container. E.g \"-e MY_VAR=my-value\"")
 
        // completion support
        configureKnownCompletions(&cmd)
@@ -94,26 +96,26 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
 
 type runCmdOptions struct {
        *RootCmdOptions
-       Compression     bool
-       Wait            bool
-       Logs            bool
-       Sync            bool
-       Dev             bool
-       IntegrationKit  string
-       IntegrationName string
-       Profile         string
-       OutputFormat    string
-       Resources       []string
-       OpenAPIs        []string
-       Dependencies    []string
-       Properties      []string
-       ConfigMaps      []string
-       Secrets         []string
-       Repositories    []string
-       Traits          []string
-       LoggingLevels   []string
-       Volumes         []string
-       EnvVars         []string
+       Compression     bool     `mapstructure:"compression"`
+       Wait            bool     `mapstructure:"wait"`
+       Logs            bool     `mapstructure:"logs"`
+       Sync            bool     `mapstructure:"sync"`
+       Dev             bool     `mapstructure:"dev"`
+       IntegrationKit  string   `mapstructure:"kit"`
+       IntegrationName string   `mapstructure:"name"`
+       Profile         string   `mapstructure:"profile"`
+       OutputFormat    string   `mapstructure:"output"`
+       Resources       []string `mapstructure:"resources"`
+       OpenAPIs        []string `mapstructure:"open-apis"`
+       Dependencies    []string `mapstructure:"dependencies"`
+       Properties      []string `mapstructure:"properties"`
+       ConfigMaps      []string `mapstructure:"configmaps"`
+       Secrets         []string `mapstructure:"secrets"`
+       Repositories    []string `mapstructure:"maven-repositories"`
+       Traits          []string `mapstructure:"traits"`
+       LoggingLevels   []string `mapstructure:"logging-levels"`
+       Volumes         []string `mapstructure:"volumes"`
+       EnvVars         []string `mapstructure:"envs"`
 }
 
 func (o *runCmdOptions) validateArgs(_ *cobra.Command, args []string) error {
@@ -232,7 +234,7 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
        }
 
        if o.Sync && !o.Logs && !o.Dev {
-               // Let's add a wait point, otherwise the script terminates
+               // Let's add a Wait point, otherwise the script terminates
                <-o.Context.Done()
        }
        return nil
@@ -241,7 +243,7 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
 func (o *runCmdOptions) waitForIntegrationReady(integration 
*v1alpha1.Integration) (*v1alpha1.IntegrationPhase, error) {
        handler := func(i *v1alpha1.Integration) bool {
                //
-               // TODO when we add health checks, we should wait until they 
are passed
+               // TODO when we add health checks, we should Wait until they 
are passed
                //
                if i.Status.Phase != "" {
                        fmt.Println("integration \""+integration.Name+"\" in 
phase", i.Status.Phase)
diff --git a/pkg/cmd/util.go b/pkg/cmd/util.go
index d6cb4ee..a32dcce 100644
--- a/pkg/cmd/util.go
+++ b/pkg/cmd/util.go
@@ -19,9 +19,21 @@ package cmd
 
 import (
        "context"
+       "encoding/csv"
+       "fmt"
+       "log"
+       "reflect"
+       "strings"
+
+       "github.com/mitchellh/mapstructure"
 
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        "github.com/apache/camel-k/pkg/client"
+       "github.com/spf13/cobra"
+       "github.com/spf13/pflag"
+       "github.com/spf13/viper"
+
+       p "github.com/gertd/go-pluralize"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
@@ -39,3 +51,135 @@ func DeleteIntegration(ctx context.Context, c 
client.Client, name string, namesp
        }
        return c.Delete(ctx, &integration)
 }
+
+func bindPFlagsHierarchy(cmd *cobra.Command) error {
+       for _, c := range cmd.Commands() {
+               if err := bindPFlags(c); err != nil {
+                       return err
+               }
+
+               if err := bindPFlagsHierarchy(c); err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func bindPFlags(cmd *cobra.Command) error {
+       prefix := pathToRoot(cmd)
+       pl := p.NewClient()
+
+       cmd.Flags().VisitAll(func(flag *pflag.Flag) {
+               name := flag.Name
+               name = strings.ReplaceAll(name, "_", "-")
+               name = strings.ReplaceAll(name, ".", "-")
+
+               if err := viper.BindPFlag(prefix+"."+name, flag); err != nil {
+                       log.Printf("error binding flag %s with prefix %s to 
viper: %v", flag.Name, prefix, err)
+               }
+
+               // this is a little bit of an hack to register plural version 
of properties
+               // based on the naming conventions used by the flag type 
because it is not
+               // possible to know what is the type of a flag
+               flagType := strings.ToUpper(flag.Value.Type())
+               if strings.Contains(flagType, "SLICE") || 
strings.Contains(flagType, "ARRAY") {
+                       if err := viper.BindPFlag(prefix+"."+pl.Plural(name), 
flag); err != nil {
+                               log.Printf("error binding plural flag %s with 
prefix %s to viper: %v", flag.Name, prefix, err)
+                       }
+               }
+       })
+
+       return nil
+}
+
+func pathToRoot(cmd *cobra.Command) string {
+       path := cmd.Name()
+
+       for current := cmd.Parent(); current != nil; current = current.Parent() 
{
+               name := current.Name()
+               name = strings.ReplaceAll(name, "_", "-")
+               name = strings.ReplaceAll(name, ".", "-")
+               path = name + "." + path
+       }
+
+       return path
+}
+
+func decodeKey(target interface{}, key string) error {
+       nodes := strings.Split(key, ".")
+       settings := viper.AllSettings()
+
+       for _, node := range nodes {
+               v := settings[node]
+
+               if v == nil {
+                       return nil
+               }
+
+               if m, ok := v.(map[string]interface{}); ok {
+                       settings = m
+               } else {
+                       return fmt.Errorf("unable to find node %s", node)
+               }
+       }
+
+       c := mapstructure.DecoderConfig{
+               Result:           target,
+               WeaklyTypedInput: true,
+               DecodeHook: mapstructure.ComposeDecodeHookFunc(
+                       mapstructure.StringToIPNetHookFunc(),
+                       mapstructure.StringToTimeDurationHookFunc(),
+                       stringToSliceHookFunc(','),
+               ),
+       }
+
+       decoder, err := mapstructure.NewDecoder(&c)
+       if err != nil {
+               return err
+       }
+
+       err = decoder.Decode(settings)
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func decode(target interface{}) func(*cobra.Command, []string) error {
+       return func(cmd *cobra.Command, args []string) error {
+               path := pathToRoot(cmd)
+               if err := decodeKey(target, path); err != nil {
+                       return err
+               }
+
+               return nil
+       }
+}
+
+func stringToSliceHookFunc(comma rune) mapstructure.DecodeHookFunc {
+       return func(
+               f reflect.Kind,
+               t reflect.Kind,
+               data interface{}) (interface{}, error) {
+               if f != reflect.String || t != reflect.Slice {
+                       return data, nil
+               }
+
+               s := data.(string)
+               s = strings.TrimPrefix(s, "[")
+               s = strings.TrimSuffix(s, "]")
+
+               if s == "" {
+                       return []string{}, nil
+               }
+
+               stringReader := strings.NewReader(s)
+               csvReader := csv.NewReader(stringReader)
+               csvReader.Comma = comma
+               csvReader.LazyQuotes = true
+
+               return csvReader.Read()
+       }
+}

Reply via email to