diff --git a/pkg/kubectl/resource/builder.go b/pkg/kubectl/resource/builder.go index ae7d9dfce2d..ef659cfbe03 100644 --- a/pkg/kubectl/resource/builder.go +++ b/pkg/kubectl/resource/builder.go @@ -540,138 +540,115 @@ func (b *Builder) visitorResult() *Result { // visit selectors if b.selector != nil { - if len(b.names) != 0 { - return &Result{err: fmt.Errorf("name cannot be provided when a selector is specified")} - } - if len(b.resourceTuples) != 0 { - return &Result{err: fmt.Errorf("selectors and the all flag cannot be used when passing resource/name arguments")} - } - if len(b.resources) == 0 { - return &Result{err: fmt.Errorf("at least one resource must be specified to use a selector")} - } - // empty selector has different error message for paths being provided - if len(b.paths) != 0 { - if b.selector.Empty() { - return &Result{err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")} - } else { - return &Result{err: fmt.Errorf("a selector may not be specified when path, URL, or stdin is provided as input")} - } - } - mappings, err := b.resourceMappings() - if err != nil { - return &Result{err: err} - } - - visitors := []Visitor{} - for _, mapping := range mappings { - client, err := b.mapper.ClientForMapping(mapping) - if err != nil { - return &Result{err: err} - } - selectorNamespace := b.namespace - if mapping.Scope.Name() != meta.RESTScopeNameNamespace { - selectorNamespace = "" - } - visitors = append(visitors, NewSelector(client, mapping, selectorNamespace, b.selector, b.export)) - } - if b.continueOnError { - return &Result{visitor: EagerVisitorList(visitors), sources: visitors} - } - return &Result{visitor: VisitorList(visitors), sources: visitors} + return b.visitBySelector() } // visit items specified by resource and name if len(b.resourceTuples) != 0 { - // if b.singular is false, this could be by default, so double-check length - // of resourceTuples to determine if in fact it is singular or not - isSingular := b.singular - if !isSingular { - isSingular = len(b.resourceTuples) == 1 - } - - if len(b.paths) != 0 { - return &Result{singular: isSingular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")} - } - if len(b.resources) != 0 { - return &Result{singular: isSingular, err: fmt.Errorf("you may not specify individual resources and bulk resources in the same call")} - } - - // retrieve one client for each resource - mappings, err := b.resourceTupleMappings() - if err != nil { - return &Result{singular: isSingular, err: err} - } - clients := make(map[string]RESTClient) - for _, mapping := range mappings { - s := fmt.Sprintf("%s/%s", mapping.GroupVersionKind.GroupVersion().String(), mapping.Resource) - if _, ok := clients[s]; ok { - continue - } - client, err := b.mapper.ClientForMapping(mapping) - if err != nil { - return &Result{err: err} - } - clients[s] = client - } - - items := []Visitor{} - for _, tuple := range b.resourceTuples { - mapping, ok := mappings[tuple.Resource] - if !ok { - return &Result{singular: isSingular, err: fmt.Errorf("resource %q is not recognized: %v", tuple.Resource, mappings)} - } - s := fmt.Sprintf("%s/%s", mapping.GroupVersionKind.GroupVersion().String(), mapping.Resource) - client, ok := clients[s] - if !ok { - return &Result{singular: isSingular, err: fmt.Errorf("could not find a client for resource %q", tuple.Resource)} - } - - selectorNamespace := b.namespace - if mapping.Scope.Name() != meta.RESTScopeNameNamespace { - selectorNamespace = "" - } else { - if len(b.namespace) == 0 { - return &Result{singular: isSingular, err: fmt.Errorf("namespace may not be empty when retrieving a resource by name")} - } - } - - info := NewInfo(client, mapping, selectorNamespace, tuple.Name, b.export) - items = append(items, info) - } - - var visitors Visitor - if b.continueOnError { - visitors = EagerVisitorList(items) - } else { - visitors = VisitorList(items) - } - return &Result{singular: isSingular, visitor: visitors, sources: items} + return b.visitByResource() } // visit items specified by name if len(b.names) != 0 { - isSingular := len(b.names) == 1 + return b.visitByName() + } - if len(b.paths) != 0 { - return &Result{singular: isSingular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")} - } - if len(b.resources) == 0 { - return &Result{singular: isSingular, err: fmt.Errorf("you must provide a resource and a resource name together")} - } - if len(b.resources) > 1 { - return &Result{singular: isSingular, err: fmt.Errorf("you must specify only one resource")} - } + // visit items specified by paths + if len(b.paths) != 0 { + return b.visitByPaths() + } - mappings, err := b.resourceMappings() - if err != nil { - return &Result{singular: isSingular, err: err} - } - mapping := mappings[0] + if len(b.resources) != 0 { + return &Result{err: fmt.Errorf("resource(s) were provided, but no name, label selector, or --all flag specified")} + } + return &Result{err: missingResourceError} +} +func (b *Builder) visitBySelector() *Result { + if len(b.names) != 0 { + return &Result{err: fmt.Errorf("name cannot be provided when a selector is specified")} + } + if len(b.resourceTuples) != 0 { + return &Result{err: fmt.Errorf("selectors and the all flag cannot be used when passing resource/name arguments")} + } + if len(b.resources) == 0 { + return &Result{err: fmt.Errorf("at least one resource must be specified to use a selector")} + } + // empty selector has different error message for paths being provided + if len(b.paths) != 0 { + if b.selector.Empty() { + return &Result{err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")} + } else { + return &Result{err: fmt.Errorf("a selector may not be specified when path, URL, or stdin is provided as input")} + } + } + mappings, err := b.resourceMappings() + if err != nil { + return &Result{err: err} + } + + visitors := []Visitor{} + for _, mapping := range mappings { client, err := b.mapper.ClientForMapping(mapping) if err != nil { return &Result{err: err} } + selectorNamespace := b.namespace + if mapping.Scope.Name() != meta.RESTScopeNameNamespace { + selectorNamespace = "" + } + visitors = append(visitors, NewSelector(client, mapping, selectorNamespace, b.selector, b.export)) + } + if b.continueOnError { + return &Result{visitor: EagerVisitorList(visitors), sources: visitors} + } + return &Result{visitor: VisitorList(visitors), sources: visitors} +} + +func (b *Builder) visitByResource() *Result { + // if b.singular is false, this could be by default, so double-check length + // of resourceTuples to determine if in fact it is singular or not + isSingular := b.singular + if !isSingular { + isSingular = len(b.resourceTuples) == 1 + } + + if len(b.paths) != 0 { + return &Result{singular: isSingular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")} + } + if len(b.resources) != 0 { + return &Result{singular: isSingular, err: fmt.Errorf("you may not specify individual resources and bulk resources in the same call")} + } + + // retrieve one client for each resource + mappings, err := b.resourceTupleMappings() + if err != nil { + return &Result{singular: isSingular, err: err} + } + clients := make(map[string]RESTClient) + for _, mapping := range mappings { + s := fmt.Sprintf("%s/%s", mapping.GroupVersionKind.GroupVersion().String(), mapping.Resource) + if _, ok := clients[s]; ok { + continue + } + client, err := b.mapper.ClientForMapping(mapping) + if err != nil { + return &Result{err: err} + } + clients[s] = client + } + + items := []Visitor{} + for _, tuple := range b.resourceTuples { + mapping, ok := mappings[tuple.Resource] + if !ok { + return &Result{singular: isSingular, err: fmt.Errorf("resource %q is not recognized: %v", tuple.Resource, mappings)} + } + s := fmt.Sprintf("%s/%s", mapping.GroupVersionKind.GroupVersion().String(), mapping.Resource) + client, ok := clients[s] + if !ok { + return &Result{singular: isSingular, err: fmt.Errorf("could not find a client for resource %q", tuple.Resource)} + } selectorNamespace := b.namespace if mapping.Scope.Name() != meta.RESTScopeNameNamespace { @@ -682,47 +659,86 @@ func (b *Builder) visitorResult() *Result { } } - visitors := []Visitor{} - for _, name := range b.names { - info := NewInfo(client, mapping, selectorNamespace, name, b.export) - visitors = append(visitors, info) - } - return &Result{singular: isSingular, visitor: VisitorList(visitors), sources: visitors} + info := NewInfo(client, mapping, selectorNamespace, tuple.Name, b.export) + items = append(items, info) } - // visit items specified by paths + var visitors Visitor + if b.continueOnError { + visitors = EagerVisitorList(items) + } else { + visitors = VisitorList(items) + } + return &Result{singular: isSingular, visitor: visitors, sources: items} +} + +func (b *Builder) visitByName() *Result { + isSingular := len(b.names) == 1 + if len(b.paths) != 0 { - singular := !b.dir && !b.stream && len(b.paths) == 1 - if len(b.resources) != 0 { - return &Result{singular: singular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify resource arguments as well")} - } - - var visitors Visitor - if b.continueOnError { - visitors = EagerVisitorList(b.paths) - } else { - visitors = VisitorList(b.paths) - } - - // only items from disk can be refetched - if b.latest { - // must flatten lists prior to fetching - if b.flatten { - visitors = NewFlattenListVisitor(visitors, b.mapper) - } - // must set namespace prior to fetching - if b.defaultNamespace { - visitors = NewDecoratedVisitor(visitors, SetNamespace(b.namespace)) - } - visitors = NewDecoratedVisitor(visitors, RetrieveLatest) - } - return &Result{singular: singular, visitor: visitors, sources: b.paths} + return &Result{singular: isSingular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify a resource by arguments as well")} + } + if len(b.resources) == 0 { + return &Result{singular: isSingular, err: fmt.Errorf("you must provide a resource and a resource name together")} + } + if len(b.resources) > 1 { + return &Result{singular: isSingular, err: fmt.Errorf("you must specify only one resource")} } + mappings, err := b.resourceMappings() + if err != nil { + return &Result{singular: isSingular, err: err} + } + mapping := mappings[0] + + client, err := b.mapper.ClientForMapping(mapping) + if err != nil { + return &Result{err: err} + } + + selectorNamespace := b.namespace + if mapping.Scope.Name() != meta.RESTScopeNameNamespace { + selectorNamespace = "" + } else { + if len(b.namespace) == 0 { + return &Result{singular: isSingular, err: fmt.Errorf("namespace may not be empty when retrieving a resource by name")} + } + } + + visitors := []Visitor{} + for _, name := range b.names { + info := NewInfo(client, mapping, selectorNamespace, name, b.export) + visitors = append(visitors, info) + } + return &Result{singular: isSingular, visitor: VisitorList(visitors), sources: visitors} +} + +func (b *Builder) visitByPaths() *Result { + singular := !b.dir && !b.stream && len(b.paths) == 1 if len(b.resources) != 0 { - return &Result{err: fmt.Errorf("resource(s) were provided, but no name, label selector, or --all flag specified")} + return &Result{singular: singular, err: fmt.Errorf("when paths, URLs, or stdin is provided as input, you may not specify resource arguments as well")} } - return &Result{err: missingResourceError} + + var visitors Visitor + if b.continueOnError { + visitors = EagerVisitorList(b.paths) + } else { + visitors = VisitorList(b.paths) + } + + // only items from disk can be refetched + if b.latest { + // must flatten lists prior to fetching + if b.flatten { + visitors = NewFlattenListVisitor(visitors, b.mapper) + } + // must set namespace prior to fetching + if b.defaultNamespace { + visitors = NewDecoratedVisitor(visitors, SetNamespace(b.namespace)) + } + visitors = NewDecoratedVisitor(visitors, RetrieveLatest) + } + return &Result{singular: singular, visitor: visitors, sources: b.paths} } // Do returns a Result object with a Visitor for the resources identified by the Builder.