dubboctl/cmd/create.go (209 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cmd import ( "errors" "fmt" "github.com/apache/dubbo-kubernetes/dubboctl/pkg/cli" "github.com/apache/dubbo-kubernetes/dubboctl/pkg/sdk" "github.com/apache/dubbo-kubernetes/dubboctl/pkg/sdk/dubbo" "github.com/apache/dubbo-kubernetes/operator/cmd/cluster" "github.com/ory/viper" "github.com/spf13/cobra" "os" "strings" ) type createArgs struct { // dirname specifies the name of the custom-created directory. dirname string // language specifies different sdk languages. language string // template specifies repository or default common. template string } func addCreateFlags(cmd *cobra.Command, tempArgs *createArgs) { cmd.PersistentFlags().StringVarP(&tempArgs.language, "language", "l", "", "java or go language") cmd.PersistentFlags().StringVarP(&tempArgs.template, "template", "t", "", "java or go sdk template") cmd.PersistentFlags().StringVar(&tempArgs.dirname, "dirname", "", "java or go sdk template custom directory name") } type bindFunc func(*cobra.Command, []string) error func bindEnv(flags ...string) bindFunc { return func(cmd *cobra.Command, args []string) (err error) { for _, flag := range flags { if err = viper.BindPFlag(flag, cmd.Flags().Lookup(flag)); err != nil { return } } viper.AutomaticEnv() return } } func CreateCmd(_ cli.Context, cmd *cobra.Command, clientFactory ClientFactory) *cobra.Command { rootArgs := &cluster.RootArgs{} tempArgs := &createArgs{} sc := sdkGenerateCmd(cmd, clientFactory) cc := &cobra.Command{ Use: "create", Short: "Create a custom dubbo sdk sample", Long: "The create command will generates dubbo sdk.", } cluster.AddFlags(cc, rootArgs) cluster.AddFlags(sc, rootArgs) addCreateFlags(sc, tempArgs) cc.AddCommand(sc) return cc } func sdkGenerateCmd(cmd *cobra.Command, clientFactory ClientFactory) *cobra.Command { return &cobra.Command{ Use: "sdk", Short: "Generate sdk samples for Dubbo supported languages", Long: "The sdk subcommand generates an sdk sample provided by Dubbo supported languages.", Example: ` # Create a java sample sdk. dubboctl create sdk --language java --template common --dirname mydubbo # Select a default java repository. dubboctl create sdk -l java -t common --dirname mydubbo # Select a java repository. dubboctl create sdk -l java -t myrepo/mydubbo --dirname myapp # Create a go sample sdk. dubboctl create sdk --language go --template common --dirname mydubbogo # Select a default go repository. dubboctl create sdk -l go -t common --dirname mydubbogo # Select a go repository. dubboctl create sdk -l go -t myrepo/mydubbo --dirname myapp `, PreRunE: bindEnv("language", "template", "dirname"), RunE: func(cmd *cobra.Command, args []string) error { return runCreate(cmd, args, clientFactory) }, } } type createConfig struct { // Path Absolute to function source Path string Runtime string Template string // Repo Uri (overrides builtin and installed) Repo string // DirName Defines a custom creation directory name。 DirName string Initialized bool } // newCreateConfig returns a config populated from the current execution context // (args, flags and environment variables) // The client constructor function is used to create a transient client for // accessing things like the current valid templates list, and uses the // current value of the config at time of prompting. func newCreateConfig(_ *cobra.Command, _ []string, _ ClientFactory) (cc createConfig, err error) { var absolutePath string absolutePath = cwd() cc = createConfig{ DirName: viper.GetString("dirname"), Path: absolutePath + "/" + viper.GetString("dirname"), Runtime: viper.GetString("language"), Template: viper.GetString("template"), Initialized: viper.GetBool("initialized"), } fmt.Printf("Name: %v\n", cc.DirName) fmt.Printf("Path: %v\n", cc.Path) fmt.Printf("Language: %v\n", cc.Runtime) fmt.Printf("Template: %v\n", cc.Template) return } func runCreate(cmd *cobra.Command, args []string, clientFactory ClientFactory) error { // Create a config based on args. Also uses the newClient to create a // temporary client for completing options such as available runtimes. createCfg, err := newCreateConfig(cmd, args, clientFactory) if err != nil { return err } // From environment variables, flags, arguments, and user prompts if --confirm // (in increasing levels of precedence) client, cancel := clientFactory() defer cancel() // a deeper validation than that which is performed when // instantiating the client with the raw config above. if err = createCfg.validate(client); err != nil { return err } // Initialization creation _, err = client.Initialize(&dubbo.DubboConfig{ Root: createCfg.Path, Name: createCfg.DirName, Runtime: createCfg.Runtime, Template: createCfg.Template, }, createCfg.Initialized, cmd) if err != nil { return err } fmt.Printf("dubbo %v sdk was successfully created.\n", createCfg.Runtime) return nil } type ErrNoRuntime error type ErrInvalidRuntime error type ErrInvalidTemplate error func (c createConfig) validate(client *sdk.Client) (err error) { if c.Runtime == "" { return noRuntimeError(client) } if c.Runtime != "" && c.Repo == "" && !isValidRuntime(client, c.Runtime) { return newInvalidRuntimeError(client, c.Runtime) } if c.Template != "" && c.Repo == "" && !isValidTemplate(client, c.Runtime, c.Template) { return newInvalidTemplateError(client, c.Runtime, c.Template) } return } func newInvalidRuntimeError(client *sdk.Client, runtime string) error { b := strings.Builder{} fmt.Fprintf(&b, "The language runtime '%v' is not recognized.\n", runtime) runtimes, err := client.Runtimes() if err != nil { return err } for _, v := range runtimes { fmt.Fprintf(&b, " %v\n", v) } return ErrInvalidRuntime(errors.New(b.String())) } // isValidTemplate determines if the given template is valid for the given runtime. func isValidTemplate(client *sdk.Client, runtime, template string) bool { if !isValidRuntime(client, runtime) { return false } templates, err := client.Templates().List(runtime) if err != nil { return false } for _, v := range templates { if v == template { return true } } return false } // isValidRuntime determines if the given language runtime is a valid choice. func isValidRuntime(client *sdk.Client, runtime string) bool { runtimes, err := client.Runtimes() if err != nil { return false } for _, v := range runtimes { if v == runtime { return true } } return false } func noRuntimeError(client *sdk.Client) error { b := strings.Builder{} fmt.Fprintln(&b, "Required flag \"language\" not set.") fmt.Fprintln(&b, "Available language runtimes are:") runtimes, err := client.Runtimes() if err != nil { return err } for _, v := range runtimes { fmt.Fprintf(&b, " %v\n", v) } return ErrNoRuntime(errors.New(b.String())) } func newInvalidTemplateError(client *sdk.Client, runtime, template string) error { b := strings.Builder{} fmt.Fprintf(&b, "The template '%v' was not found for language runtime '%v'.\n", template, runtime) fmt.Fprintln(&b, "Available templates for this language runtime are:") templates, err := client.Templates().List(runtime) if err != nil { return err } for _, v := range templates { fmt.Fprintf(&b, " %v\n", v) } return ErrInvalidTemplate(errors.New(b.String())) } func cwd() (cwd string) { cwd, err := os.Getwd() if err != nil { panic(fmt.Sprintf("Unable to determine current working directory: %v", err)) } return cwd }