type ExplainOptions struct {//explain结构体 genericclioptions.IOStreams CmdParent string APIVersion string Recursive bool Mapper meta.RESTMapper Schema openapi.Resources }
func NewExplainOptions(parent string, streams genericclioptions.IOStreams) *ExplainOptions { return &ExplainOptions{//初始化explain结构体 IOStreams: streams, CmdParent: parent, } }
//创建explain命令 func NewCmdExplain(parent string, f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command { o := NewExplainOptions(parent, streams)//初始化结构体 cmd := &cobra.Command{//创建cobra命令 Use: "explain RESOURCE", DisableFlagsInUseLine: true, Short: i18n.T("Documentation of resources"), Long: explainLong + "\n\n" + cmdutil.SuggestAPIResources(parent), Example: explainExamples, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Complete(f, cmd))//准备 cmdutil.CheckErr(o.Validate(args))//校验 cmdutil.CheckErr(o.Run(args))//运行 }, } cmd.Flags().BoolVar(&o.Recursive, "recursive", o.Recursive, "Print the fields of fields (Currently only 1 level deep)")//recursive选项 cmd.Flags().StringVar(&o.APIVersion, "api-version", o.APIVersion, "Get different explanations for particular API version")//api-version选项 return cmd }
//准备方法 func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { var err error o.Mapper, err = f.ToRESTMapper()//设置mapper if err != nil { return err } o.Schema, err = f.OpenAPISchema()//设置schema if err != nil { return err } return nil }
//校验 func (o *ExplainOptions) Validate(args []string) error { if len(args) == 0 {//参数不能为空 return fmt.Errorf("You must specify the type of resource to explain. %s\n", cmdutil.SuggestAPIResources(o.CmdParent)) } if len(args) > 1 {//参数不能大于一个 return fmt.Errorf("We accept only this format: explain RESOURCE\n") } return nil }
//运行 func (o *ExplainOptions) Run(args []string) error { recursive := o.Recursive apiVersionString := o.APIVersion // TODO: After we figured out the new syntax to separate group and resource, allow // the users to use it in explain (kubectl explain <group><syntax><resource>). // Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax. inModel, fieldsPath, err := explain.SplitAndParseResourceRequest(args[0], o.Mapper)//用.分割resource和字段 if err != nil { return err } // TODO: We should deduce the group for a resource by discovering the supported resources at server. fullySpecifiedGVR, groupResource := schema.ParseResourceArg(inModel)//解析groupversionresource gvk := schema.GroupVersionKind{} if fullySpecifiedGVR != nil { gvk, _ = o.Mapper.KindFor(*fullySpecifiedGVR)//从gvr获取gvk } if gvk.Empty() {//如果gvk为空,则获取版本为空的gvk gvk, err = o.Mapper.KindFor(groupResource.WithVersion("")) if err != nil { return err } } if len(apiVersionString) != 0 {//如果api-version不为空,则再次获取gvk apiVersion, err := schema.ParseGroupVersion(apiVersionString) if err != nil { return err } gvk = apiVersion.WithKind(gvk.Kind) } schema := o.Schema.LookupResource(gvk)//获取schema if schema == nil { return fmt.Errorf("Couldn't find resource for %q", gvk) } return explain.PrintModelDescription(fieldsPath, o.Out, schema, gvk, recursive)//打印结果 }