Commit 5c3791b9 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #41729 from smarterclayton/refactor_printers

Automatic merge from submit-queue (batch tested with PRs 41621, 41946, 41941, 41250, 41729) Refactor printers and describers into their own package. This sets the stage for using printer code from the server side (decoupled from kubectl) and loosens the coupling between kubectl and the printers. `pkg/printers` contains interfaces and has an import restriction against pulling in API specific code, while `pkg/printers/internalversion` can be used for internal types. Add a method on `Factory` for retrieving PrinterForCommand which uses the Scheme and RESTMapper from the Factory, not the hardcoded ones. This further separates kubectl from the core API scheme and allows better composition. Change NamePrinter to use RESTMapper (previously it was hardcoding those conversions). This means that we now return plural resource names (`pods/foo`) but is correct once aliases and shortnames start being returned by the mapper. This is a prerequisite for server side get, but is pure refactor (contains no new features). @deads2k @liggitt
parents 3f4ef9ae 651188d6
...@@ -38,8 +38,8 @@ go_library( ...@@ -38,8 +38,8 @@ go_library(
"//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//cmd/kubeadm/app/util/token:go_default_library", "//cmd/kubeadm/app/util/token:go_default_library",
"//pkg/bootstrap/api:go_default_library", "//pkg/bootstrap/api:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/util/initsystem:go_default_library", "//pkg/util/initsystem:go_default_library",
"//pkg/version:go_default_library", "//pkg/version:go_default_library",
"//vendor:github.com/blang/semver", "//vendor:github.com/blang/semver",
......
...@@ -37,7 +37,7 @@ import ( ...@@ -37,7 +37,7 @@ import (
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token" tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token"
bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api" bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/printers"
) )
func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command { func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command {
...@@ -207,7 +207,7 @@ func RunListTokens(out io.Writer, errW io.Writer, cmd *cobra.Command) error { ...@@ -207,7 +207,7 @@ func RunListTokens(out io.Writer, errW io.Writer, cmd *cobra.Command) error {
if err != nil { if err != nil {
return fmt.Errorf("error parsing expiration time [%v]", err) return fmt.Errorf("error parsing expiration time [%v]", err)
} }
expires = kubectl.ShortHumanDuration(expireTime.Sub(time.Now())) expires = printers.ShortHumanDuration(expireTime.Sub(time.Now()))
} }
fmt.Fprintf(w, "%s\t%s\t%s\n", tokenId, tokenutil.BearerToken(td), expires) fmt.Fprintf(w, "%s\t%s\t%s\n", tokenId, tokenutil.BearerToken(td), expires)
} }
......
...@@ -180,6 +180,7 @@ pkg/kubelet/volumemanager/cache ...@@ -180,6 +180,7 @@ pkg/kubelet/volumemanager/cache
pkg/kubelet/volumemanager/populator pkg/kubelet/volumemanager/populator
pkg/kubelet/volumemanager/reconciler pkg/kubelet/volumemanager/reconciler
pkg/labels pkg/labels
pkg/printers
pkg/proxy/config pkg/proxy/config
pkg/proxy/healthcheck pkg/proxy/healthcheck
pkg/quota pkg/quota
......
...@@ -92,6 +92,7 @@ filegroup( ...@@ -92,6 +92,7 @@ filegroup(
"//pkg/labels:all-srcs", "//pkg/labels:all-srcs",
"//pkg/master:all-srcs", "//pkg/master:all-srcs",
"//pkg/metrics:all-srcs", "//pkg/metrics:all-srcs",
"//pkg/printers:all-srcs",
"//pkg/probe:all-srcs", "//pkg/probe:all-srcs",
"//pkg/proxy:all-srcs", "//pkg/proxy:all-srcs",
"//pkg/quota:all-srcs", "//pkg/quota:all-srcs",
......
...@@ -13,7 +13,7 @@ go_library( ...@@ -13,7 +13,7 @@ go_library(
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/kubectl:go_default_library", "//pkg/printers:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/util/validation/field", "//vendor:k8s.io/apimachinery/pkg/util/validation/field",
......
...@@ -30,7 +30,7 @@ import ( ...@@ -30,7 +30,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/printers"
) )
// Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go // Based on: https://github.com/openshift/origin/blob/master/pkg/api/compatibility_test.go
...@@ -94,7 +94,7 @@ func TestCompatibility( ...@@ -94,7 +94,7 @@ func TestCompatibility(
} }
if hasError { if hasError {
printer := new(kubectl.JSONPrinter) printer := &printers.JSONPrinter{}
printer.PrintObj(obj, os.Stdout) printer.PrintObj(obj, os.Stdout)
t.Logf("2: Encoded value: %#v", string(output)) t.Logf("2: Encoded value: %#v", string(output))
} }
......
...@@ -63,6 +63,7 @@ go_test( ...@@ -63,6 +63,7 @@ go_test(
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/install:go_default_library",
"//pkg/api/testing/compat:go_default_library", "//pkg/api/testing/compat:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/api/validation:go_default_library", "//pkg/api/validation:go_default_library",
......
...@@ -25,6 +25,8 @@ import ( ...@@ -25,6 +25,8 @@ import (
"k8s.io/kubernetes/pkg/api/testing/compat" "k8s.io/kubernetes/pkg/api/testing/compat"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/validation" "k8s.io/kubernetes/pkg/api/validation"
_ "k8s.io/kubernetes/pkg/api/install"
) )
func TestCompatibility_v1_PodSecurityContext(t *testing.T) { func TestCompatibility_v1_PodSecurityContext(t *testing.T) {
......
...@@ -17,9 +17,7 @@ go_library( ...@@ -17,9 +17,7 @@ go_library(
"cluster.go", "cluster.go",
"clusterrolebinding.go", "clusterrolebinding.go",
"configmap.go", "configmap.go",
"custom_column_printer.go",
"deployment.go", "deployment.go",
"describe.go",
"doc.go", "doc.go",
"explain.go", "explain.go",
"generate.go", "generate.go",
...@@ -31,7 +29,6 @@ go_library( ...@@ -31,7 +29,6 @@ go_library(
"proxy_server.go", "proxy_server.go",
"quota.go", "quota.go",
"resource_filter.go", "resource_filter.go",
"resource_printer.go",
"rolebinding.go", "rolebinding.go",
"rollback.go", "rollback.go",
"rolling_updater.go", "rolling_updater.go",
...@@ -44,31 +41,24 @@ go_library( ...@@ -44,31 +41,24 @@ go_library(
"service.go", "service.go",
"service_basic.go", "service_basic.go",
"serviceaccount.go", "serviceaccount.go",
"sorted_resource_name_list.go",
"sorting_printer.go", "sorting_printer.go",
"stop.go", "stop.go",
"versioned_client.go", "versioned_client.go",
], ],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//federation/apis/federation:go_default_library",
"//federation/apis/federation/v1beta1:go_default_library", "//federation/apis/federation/v1beta1:go_default_library",
"//federation/client/clientset_generated/federation_internalclientset:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/annotations:go_default_library", "//pkg/api/annotations:go_default_library",
"//pkg/api/events:go_default_library",
"//pkg/api/util:go_default_library", "//pkg/api/util:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/apis/apps:go_default_library", "//pkg/apis/apps:go_default_library",
"//pkg/apis/autoscaling:go_default_library", "//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/batch:go_default_library", "//pkg/apis/batch:go_default_library",
"//pkg/apis/certificates:go_default_library",
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/apis/policy:go_default_library", "//pkg/apis/policy:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/storage:go_default_library",
"//pkg/apis/storage/util:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library", "//pkg/client/clientset_generated/clientset:go_default_library",
"//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library", "//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library",
"//pkg/client/clientset_generated/clientset/typed/extensions/v1beta1:go_default_library", "//pkg/client/clientset_generated/clientset/typed/extensions/v1beta1:go_default_library",
...@@ -81,14 +71,12 @@ go_library( ...@@ -81,14 +71,12 @@ go_library(
"//pkg/client/unversioned:go_default_library", "//pkg/client/unversioned:go_default_library",
"//pkg/controller/deployment/util:go_default_library", "//pkg/controller/deployment/util:go_default_library",
"//pkg/credentialprovider:go_default_library", "//pkg/credentialprovider:go_default_library",
"//pkg/fieldpath:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/kubelet/qos:go_default_library", "//pkg/printers:go_default_library",
"//pkg/printers/internalversion:go_default_library",
"//pkg/util:go_default_library", "//pkg/util:go_default_library",
"//pkg/util/node:go_default_library",
"//pkg/util/slice:go_default_library", "//pkg/util/slice:go_default_library",
"//vendor:github.com/emicklei/go-restful/swagger", "//vendor:github.com/emicklei/go-restful/swagger",
"//vendor:github.com/ghodss/yaml",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:github.com/spf13/cobra", "//vendor:github.com/spf13/cobra",
"//vendor:github.com/spf13/pflag", "//vendor:github.com/spf13/pflag",
...@@ -104,12 +92,10 @@ go_library( ...@@ -104,12 +92,10 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/types", "//vendor:k8s.io/apimachinery/pkg/types",
"//vendor:k8s.io/apimachinery/pkg/util/errors", "//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apimachinery/pkg/util/intstr", "//vendor:k8s.io/apimachinery/pkg/util/intstr",
"//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apimachinery/pkg/util/uuid", "//vendor:k8s.io/apimachinery/pkg/util/uuid",
"//vendor:k8s.io/apimachinery/pkg/util/validation", "//vendor:k8s.io/apimachinery/pkg/util/validation",
"//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apimachinery/pkg/util/wait",
"//vendor:k8s.io/apimachinery/pkg/watch", "//vendor:k8s.io/apimachinery/pkg/watch",
"//vendor:k8s.io/client-go/dynamic",
"//vendor:k8s.io/client-go/rest", "//vendor:k8s.io/client-go/rest",
"//vendor:k8s.io/client-go/util/integer", "//vendor:k8s.io/client-go/util/integer",
"//vendor:k8s.io/client-go/util/jsonpath", "//vendor:k8s.io/client-go/util/jsonpath",
...@@ -121,15 +107,12 @@ go_test( ...@@ -121,15 +107,12 @@ go_test(
srcs = [ srcs = [
"cluster_test.go", "cluster_test.go",
"configmap_test.go", "configmap_test.go",
"custom_column_printer_test.go",
"deployment_test.go", "deployment_test.go",
"describe_test.go",
"generate_test.go", "generate_test.go",
"kubectl_test.go", "kubectl_test.go",
"namespace_test.go", "namespace_test.go",
"proxy_server_test.go", "proxy_server_test.go",
"quota_test.go", "quota_test.go",
"resource_printer_test.go",
"rolling_updater_test.go", "rolling_updater_test.go",
"rollout_status_test.go", "rollout_status_test.go",
"run_test.go", "run_test.go",
...@@ -140,46 +123,32 @@ go_test( ...@@ -140,46 +123,32 @@ go_test(
"service_basic_test.go", "service_basic_test.go",
"service_test.go", "service_test.go",
"serviceaccount_test.go", "serviceaccount_test.go",
"sorted_resource_name_list_test.go",
"sorting_printer_test.go", "sorting_printer_test.go",
"stop_test.go", "stop_test.go",
], ],
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//federation/apis/federation:go_default_library",
"//federation/apis/federation/v1beta1:go_default_library", "//federation/apis/federation/v1beta1:go_default_library",
"//federation/client/clientset_generated/federation_internalclientset/fake:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/testapi:go_default_library", "//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library", "//pkg/api/testing:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
"//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/batch:go_default_library", "//pkg/apis/batch:go_default_library",
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/apis/storage:go_default_library",
"//pkg/client/clientset_generated/clientset/fake:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/batch/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library",
"//pkg/controller/deployment/util:go_default_library", "//pkg/controller/deployment/util:go_default_library",
"//pkg/kubectl/testing:go_default_library",
"//pkg/util:go_default_library",
"//vendor:github.com/ghodss/yaml",
"//vendor:github.com/spf13/cobra", "//vendor:github.com/spf13/cobra",
"//vendor:k8s.io/apimachinery/pkg/api/equality",
"//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/api/resource", "//vendor:k8s.io/apimachinery/pkg/api/resource",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/yaml",
"//vendor:k8s.io/apimachinery/pkg/util/diff",
"//vendor:k8s.io/apimachinery/pkg/util/intstr", "//vendor:k8s.io/apimachinery/pkg/util/intstr",
"//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apimachinery/pkg/watch", "//vendor:k8s.io/apimachinery/pkg/watch",
......
...@@ -90,6 +90,8 @@ go_library( ...@@ -90,6 +90,8 @@ go_library(
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/kubelet/server/remotecommand:go_default_library", "//pkg/kubelet/server/remotecommand:go_default_library",
"//pkg/kubelet/types:go_default_library", "//pkg/kubelet/types:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/printers/internalversion:go_default_library",
"//pkg/util/crlf:go_default_library", "//pkg/util/crlf:go_default_library",
"//pkg/util/exec:go_default_library", "//pkg/util/exec:go_default_library",
"//pkg/util/i18n:go_default_library", "//pkg/util/i18n:go_default_library",
...@@ -198,6 +200,8 @@ go_test( ...@@ -198,6 +200,8 @@ go_test(
"//pkg/kubectl/cmd/testing:go_default_library", "//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/printers/internalversion:go_default_library",
"//pkg/util/strings:go_default_library", "//pkg/util/strings:go_default_library",
"//pkg/util/term:go_default_library", "//pkg/util/term:go_default_library",
"//vendor:github.com/spf13/cobra", "//vendor:github.com/spf13/cobra",
...@@ -208,6 +212,7 @@ go_test( ...@@ -208,6 +212,7 @@ go_test(
"//vendor:k8s.io/apimachinery/pkg/api/meta", "//vendor:k8s.io/apimachinery/pkg/api/meta",
"//vendor:k8s.io/apimachinery/pkg/api/resource", "//vendor:k8s.io/apimachinery/pkg/api/resource",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/json", "//vendor:k8s.io/apimachinery/pkg/runtime/serializer/json",
......
...@@ -36,6 +36,7 @@ import ( ...@@ -36,6 +36,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
) )
...@@ -101,7 +102,7 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -101,7 +102,7 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs, argAliases := []string{}, []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, kubectl.PrintOptions{ p, err := f.Printer(nil, printers.PrintOptions{
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
......
...@@ -26,9 +26,9 @@ import ( ...@@ -26,9 +26,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
) )
...@@ -93,10 +93,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, args []string, out i ...@@ -93,10 +93,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, args []string, out i
return err return err
} }
printer, _, err := kubectl.GetPrinter("json", "", false, true) printer := &printers.JSONPrinter{}
if err != nil {
return err
}
nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{}) nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{})
if err != nil { if err != nil {
......
...@@ -35,9 +35,10 @@ import ( ...@@ -35,9 +35,10 @@ import (
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/kubectl"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/printers"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
"k8s.io/kubernetes/pkg/util/strings" "k8s.io/kubernetes/pkg/util/strings"
) )
...@@ -97,12 +98,12 @@ func (t *testPrinter) AfterPrint(output io.Writer, res string) error { ...@@ -97,12 +98,12 @@ func (t *testPrinter) AfterPrint(output io.Writer, res string) error {
type testDescriber struct { type testDescriber struct {
Name, Namespace string Name, Namespace string
Settings kubectl.DescriberSettings Settings printers.DescriberSettings
Output string Output string
Err error Err error
} }
func (t *testDescriber) Describe(namespace, name string, describerSettings kubectl.DescriberSettings) (output string, err error) { func (t *testDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (output string, err error) {
t.Namespace, t.Name = namespace, name t.Namespace, t.Name = namespace, name
t.Settings = describerSettings t.Settings = describerSettings
return t.Output, t.Err return t.Output, t.Err
...@@ -146,10 +147,12 @@ func stringBody(body string) io.ReadCloser { ...@@ -146,10 +147,12 @@ func stringBody(body string) io.ReadCloser {
func Example_printReplicationControllerWithNamespace() { func Example_printReplicationControllerWithNamespace() {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ p := printers.NewHumanReadablePrinter(printers.PrintOptions{
WithNamespace: true, WithNamespace: true,
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
printersinternal.AddHandlers(p)
tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -197,10 +200,12 @@ func Example_printReplicationControllerWithNamespace() { ...@@ -197,10 +200,12 @@ func Example_printReplicationControllerWithNamespace() {
func Example_printMultiContainersReplicationControllerWithWide() { func Example_printMultiContainersReplicationControllerWithWide() {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ p := printers.NewHumanReadablePrinter(printers.PrintOptions{
Wide: true, Wide: true,
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
printersinternal.AddHandlers(p)
tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -250,9 +255,11 @@ func Example_printMultiContainersReplicationControllerWithWide() { ...@@ -250,9 +255,11 @@ func Example_printMultiContainersReplicationControllerWithWide() {
func Example_printReplicationController() { func Example_printReplicationController() {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ p := printers.NewHumanReadablePrinter(printers.PrintOptions{
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
printersinternal.AddHandlers(p)
tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -302,10 +309,12 @@ func Example_printReplicationController() { ...@@ -302,10 +309,12 @@ func Example_printReplicationController() {
func Example_printPodWithWideFormat() { func Example_printPodWithWideFormat() {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ p := printers.NewHumanReadablePrinter(printers.PrintOptions{
Wide: true, Wide: true,
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
printersinternal.AddHandlers(p)
tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -343,10 +352,12 @@ func Example_printPodWithWideFormat() { ...@@ -343,10 +352,12 @@ func Example_printPodWithWideFormat() {
func Example_printPodWithShowLabels() { func Example_printPodWithShowLabels() {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ p := printers.NewHumanReadablePrinter(printers.PrintOptions{
ShowLabels: true, ShowLabels: true,
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
printersinternal.AddHandlers(p)
tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -479,9 +490,11 @@ func newAllPhasePodList() *api.PodList { ...@@ -479,9 +490,11 @@ func newAllPhasePodList() *api.PodList {
func Example_printPodHideTerminated() { func Example_printPodHideTerminated() {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ p := printers.NewHumanReadablePrinter(printers.PrintOptions{
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
printersinternal.AddHandlers(p)
tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -512,10 +525,12 @@ func Example_printPodHideTerminated() { ...@@ -512,10 +525,12 @@ func Example_printPodHideTerminated() {
func Example_printPodShowAll() { func Example_printPodShowAll() {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ p := printers.NewHumanReadablePrinter(printers.PrintOptions{
ShowAll: true, ShowAll: true,
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
printersinternal.AddHandlers(p)
tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -539,10 +554,12 @@ func Example_printPodShowAll() { ...@@ -539,10 +554,12 @@ func Example_printPodShowAll() {
func Example_printServiceWithNamespacesAndLabels() { func Example_printServiceWithNamespacesAndLabels() {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, _, ns := cmdtesting.NewAPIFactory()
tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ p := printers.NewHumanReadablePrinter(printers.PrintOptions{
WithNamespace: true, WithNamespace: true,
ColumnLabels: []string{"l1"}, ColumnLabels: []string{"l1"},
}) })
printersinternal.AddHandlers(p)
tf.Printer = p
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
......
...@@ -28,11 +28,13 @@ go_library( ...@@ -28,11 +28,13 @@ go_library(
], ],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library", "//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/util/i18n:go_default_library", "//pkg/util/i18n:go_default_library",
"//vendor:github.com/spf13/cobra", "//vendor:github.com/spf13/cobra",
"//vendor:k8s.io/apimachinery/pkg/api/meta",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/util/errors", "//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apiserver/pkg/util/flag", "//vendor:k8s.io/apiserver/pkg/util/flag",
......
...@@ -52,7 +52,7 @@ func NewCmdConfig(pathOptions *clientcmd.PathOptions, out, errOut io.Writer) *co ...@@ -52,7 +52,7 @@ func NewCmdConfig(pathOptions *clientcmd.PathOptions, out, errOut io.Writer) *co
// file paths are common to all sub commands // file paths are common to all sub commands
cmd.PersistentFlags().StringVar(&pathOptions.LoadingRules.ExplicitPath, pathOptions.ExplicitFileFlag, pathOptions.LoadingRules.ExplicitPath, "use a particular kubeconfig file") cmd.PersistentFlags().StringVar(&pathOptions.LoadingRules.ExplicitPath, pathOptions.ExplicitFileFlag, pathOptions.LoadingRules.ExplicitPath, "use a particular kubeconfig file")
cmd.AddCommand(NewCmdConfigView(out, pathOptions)) cmd.AddCommand(NewCmdConfigView(out, errOut, pathOptions))
cmd.AddCommand(NewCmdConfigSetCluster(out, pathOptions)) cmd.AddCommand(NewCmdConfigSetCluster(out, pathOptions))
cmd.AddCommand(NewCmdConfigSetAuthInfo(out, pathOptions)) cmd.AddCommand(NewCmdConfigSetAuthInfo(out, pathOptions))
cmd.AddCommand(NewCmdConfigSetContext(out, pathOptions)) cmd.AddCommand(NewCmdConfigSetContext(out, pathOptions))
......
...@@ -23,13 +23,14 @@ import ( ...@@ -23,13 +23,14 @@ import (
"text/tabwriter" "text/tabwriter"
"github.com/spf13/cobra" "github.com/spf13/cobra"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
) )
...@@ -108,7 +109,7 @@ func (o GetContextsOptions) RunGetContexts() error { ...@@ -108,7 +109,7 @@ func (o GetContextsOptions) RunGetContexts() error {
out, found := o.out.(*tabwriter.Writer) out, found := o.out.(*tabwriter.Writer)
if !found { if !found {
out = kubectl.GetNewTabWriter(o.out) out = printers.GetNewTabWriter(o.out)
defer out.Flush() defer out.Flush()
} }
......
...@@ -23,13 +23,15 @@ import ( ...@@ -23,13 +23,15 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/util/flag" "k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/tools/clientcmd/api/latest" "k8s.io/client-go/tools/clientcmd/api/latest"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
) )
...@@ -55,7 +57,7 @@ var ( ...@@ -55,7 +57,7 @@ var (
kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`) kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`)
) )
func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command { func NewCmdConfigView(out, errOut io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command {
options := &ViewOptions{ConfigAccess: ConfigAccess} options := &ViewOptions{ConfigAccess: ConfigAccess}
// Default to yaml // Default to yaml
defaultOutputFormat := "yaml" defaultOutputFormat := "yaml"
...@@ -69,17 +71,19 @@ func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra ...@@ -69,17 +71,19 @@ func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra
options.Complete() options.Complete()
outputFormat := cmdutil.GetFlagString(cmd, "output") outputFormat := cmdutil.GetFlagString(cmd, "output")
if outputFormat == "wide" { if outputFormat == "wide" {
fmt.Printf("--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat) fmt.Fprintf(errOut, "--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat)
// TODO: once printing is abstracted, this should be handled at flag declaration time
cmd.Flags().Set("output", defaultOutputFormat) cmd.Flags().Set("output", defaultOutputFormat)
} }
if outputFormat == "" { if outputFormat == "" {
fmt.Printf("Reset to default output format (%s) as --output is empty\n", defaultOutputFormat) fmt.Fprintf(errOut, "Reset to default output format (%s) as --output is empty\n", defaultOutputFormat)
// TODO: once printing is abstracted, this should be handled at flag declaration time
cmd.Flags().Set("output", defaultOutputFormat) cmd.Flags().Set("output", defaultOutputFormat)
} }
printer, _, err := cmdutil.PrinterForCommand(cmd) printer, _, err := cmdutil.PrinterForCommand(cmd, meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, []runtime.Decoder{latest.Codec})
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
printer = kubectl.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion) printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion)
cmdutil.CheckErr(options.Run(out, printer)) cmdutil.CheckErr(options.Run(out, printer))
}, },
...@@ -97,7 +101,7 @@ func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra ...@@ -97,7 +101,7 @@ func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra
return cmd return cmd
} }
func (o ViewOptions) Run(out io.Writer, printer kubectl.ResourcePrinter) error { func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error {
config, err := o.loadConfig() config, err := o.loadConfig()
if err != nil { if err != nil {
return err return err
......
...@@ -25,10 +25,10 @@ import ( ...@@ -25,10 +25,10 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -96,7 +96,7 @@ type ConvertOptions struct { ...@@ -96,7 +96,7 @@ type ConvertOptions struct {
encoder runtime.Encoder encoder runtime.Encoder
out io.Writer out io.Writer
printer kubectl.ResourcePrinter printer printers.ResourcePrinter
outputVersion schema.GroupVersion outputVersion schema.GroupVersion
} }
...@@ -160,9 +160,11 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C ...@@ -160,9 +160,11 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
} else { } else {
outputFormat = "template" outputFormat = "template"
} }
// TODO: once printing is abstracted, this should be handled at flag declaration time
cmd.Flags().Set("output", outputFormat)
} }
o.encoder = f.JSONEncoder() o.encoder = f.JSONEncoder()
o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile, false, cmdutil.GetFlagBool(cmd, "allow-missing-template-keys")) o.printer, _, err = f.PrinterForCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -32,6 +32,7 @@ import ( ...@@ -32,6 +32,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
) )
...@@ -117,7 +118,7 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { ...@@ -117,7 +118,7 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs, argAliases := []string{}, []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, kubectl.PrintOptions{ p, err := f.Printer(nil, printers.PrintOptions{
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
......
...@@ -33,6 +33,8 @@ import ( ...@@ -33,6 +33,8 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
) )
...@@ -72,9 +74,11 @@ var ( ...@@ -72,9 +74,11 @@ var (
func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command { func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
options := &resource.FilenameOptions{} options := &resource.FilenameOptions{}
describerSettings := &kubectl.DescriberSettings{} describerSettings := &printers.DescriberSettings{}
validArgs := kubectl.DescribableResources() // TODO: this should come from the factory, and may need to be loaded from the server, and so is probably
// going to have to be removed
validArgs := printersinternal.DescribableResources()
argAliases := kubectl.ResourceAliases(validArgs) argAliases := kubectl.ResourceAliases(validArgs)
cmd := &cobra.Command{ cmd := &cobra.Command{
...@@ -98,7 +102,7 @@ func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command { ...@@ -98,7 +102,7 @@ func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command {
return cmd return cmd
} }
func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions, describerSettings *kubectl.DescriberSettings) error { func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions, describerSettings *printers.DescriberSettings) error {
selector := cmdutil.GetFlagString(cmd, "selector") selector := cmdutil.GetFlagString(cmd, "selector")
allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces") allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
cmdNamespace, enforceNamespace, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
...@@ -172,7 +176,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a ...@@ -172,7 +176,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
return utilerrors.NewAggregate(allErrs) return utilerrors.NewAggregate(allErrs)
} }
func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *kubectl.DescriberSettings, out io.Writer, originalError error) error { func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *printers.DescriberSettings, out io.Writer, originalError error) error {
mapper, typer, err := f.UnstructuredObject() mapper, typer, err := f.UnstructuredObject()
if err != nil { if err != nil {
return err return err
......
...@@ -43,6 +43,7 @@ import ( ...@@ -43,6 +43,7 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor" "k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/crlf" "k8s.io/kubernetes/pkg/util/crlf"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
...@@ -64,9 +65,9 @@ var ( ...@@ -64,9 +65,9 @@ var (
Editing is done with the API version used to fetch the resource. Editing is done with the API version used to fetch the resource.
To edit using a specific API version, fully-qualify the resource, version, and group. To edit using a specific API version, fully-qualify the resource, version, and group.
The default format is YAML. To edit in JSON, specify "-o json". The default format is YAML. To edit in JSON, specify "-o json".
The flag --windows-line-endings can be used to force Windows line endings, The flag --windows-line-endings can be used to force Windows line endings,
otherwise the default for your operating system will be used. otherwise the default for your operating system will be used.
...@@ -92,7 +93,7 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { ...@@ -92,7 +93,7 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs, argAliases := []string{}, []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, kubectl.PrintOptions{ p, err := f.Printer(nil, printers.PrintOptions{
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
...@@ -343,14 +344,14 @@ func getPrinter(cmd *cobra.Command) (*editPrinterOptions, error) { ...@@ -343,14 +344,14 @@ func getPrinter(cmd *cobra.Command) (*editPrinterOptions, error) {
switch format := cmdutil.GetFlagString(cmd, "output"); format { switch format := cmdutil.GetFlagString(cmd, "output"); format {
case "json": case "json":
return &editPrinterOptions{ return &editPrinterOptions{
printer: &kubectl.JSONPrinter{}, printer: &printers.JSONPrinter{},
ext: ".json", ext: ".json",
addHeader: false, addHeader: false,
}, nil }, nil
// If flag -o is not specified, use yaml as default // If flag -o is not specified, use yaml as default
case "yaml", "": case "yaml", "":
return &editPrinterOptions{ return &editPrinterOptions{
printer: &kubectl.YAMLPrinter{}, printer: &printers.YAMLPrinter{},
ext: ".yaml", ext: ".yaml",
addHeader: true, addHeader: true,
}, nil }, nil
...@@ -589,7 +590,7 @@ func (h *editHeader) flush() { ...@@ -589,7 +590,7 @@ func (h *editHeader) flush() {
} }
type editPrinterOptions struct { type editPrinterOptions struct {
printer kubectl.ResourcePrinter printer printers.ResourcePrinter
ext string ext string
addHeader bool addHeader bool
} }
......
...@@ -28,8 +28,8 @@ import ( ...@@ -28,8 +28,8 @@ import (
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubectl"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/printers"
) )
func TestRunExposeService(t *testing.T) { func TestRunExposeService(t *testing.T) {
...@@ -460,7 +460,7 @@ func TestRunExposeService(t *testing.T) { ...@@ -460,7 +460,7 @@ func TestRunExposeService(t *testing.T) {
for _, test := range tests { for _, test := range tests {
f, tf, codec, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Printer = &kubectl.JSONPrinter{} tf.Printer = &printers.JSONPrinter{}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
......
...@@ -34,6 +34,7 @@ import ( ...@@ -34,6 +34,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
"k8s.io/kubernetes/pkg/util/interrupt" "k8s.io/kubernetes/pkg/util/interrupt"
) )
...@@ -95,7 +96,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman ...@@ -95,7 +96,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs, argAliases := []string{}, []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, kubectl.PrintOptions{ p, err := f.Printer(nil, printers.PrintOptions{
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
...@@ -303,7 +304,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ ...@@ -303,7 +304,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
return err return err
} }
printer, generic, err := cmdutil.PrinterForCommand(cmd) printer, generic, err := f.PrinterForCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
...@@ -430,7 +431,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ ...@@ -430,7 +431,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
// use the default printer for each object // use the default printer for each object
printer = nil printer = nil
var lastMapping *meta.RESTMapping var lastMapping *meta.RESTMapping
w := kubectl.GetNewTabWriter(out) w := printers.GetNewTabWriter(out)
filteredResourceCount := 0 filteredResourceCount := 0
if resource.MultipleTypesRequested(args) || cmdutil.MustPrintWithKinds(objs, infos, sorter) { if resource.MultipleTypesRequested(args) || cmdutil.MustPrintWithKinds(objs, infos, sorter) {
...@@ -486,7 +487,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ ...@@ -486,7 +487,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
} }
} }
if resourcePrinter, found := printer.(*kubectl.HumanReadablePrinter); found { if resourcePrinter, found := printer.(*printers.HumanReadablePrinter); found {
resourceName := resourcePrinter.GetResourceKind() resourceName := resourcePrinter.GetResourceKind()
if mapping != nil { if mapping != nil {
if resourceName == "" { if resourceName == "" {
......
...@@ -29,6 +29,7 @@ import ( ...@@ -29,6 +29,7 @@ import (
apiequality "k8s.io/apimachinery/pkg/api/equality" apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/json" "k8s.io/apimachinery/pkg/runtime/serializer/json"
...@@ -506,7 +507,8 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) { ...@@ -506,7 +507,8 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
pods, svc, _ := testData() pods, svc, _ := testData()
f, tf, codec, _ := cmdtesting.NewAPIFactory() f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{} tf.CommandPrinter = &testPrinter{}
tf.GenericPrinter = true
tf.UnstructuredClient = &fake.RESTClient{ tf.UnstructuredClient = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: unstructuredSerializer, NegotiatedSerializer: unstructuredSerializer,
...@@ -533,34 +535,37 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) { ...@@ -533,34 +535,37 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
cmd.Flags().Set("output", "json") cmd.Flags().Set("output", "json")
cmd.Run(cmd, []string{"pods,services"}) cmd.Run(cmd, []string{"pods,services"})
if tf.Printer.(*testPrinter).Objects != nil { actual := tf.CommandPrinter.(*testPrinter).Objects
t.Errorf("unexpected print to default printer") fn := func(obj runtime.Object) *unstructured.Unstructured {
data, err := runtime.Encode(api.Codecs.LegacyCodec(schema.GroupVersion{Version: "v1"}), obj)
if err != nil {
panic(err)
}
out := &unstructured.Unstructured{Object: make(map[string]interface{})}
if err := encjson.Unmarshal(data, &out.Object); err != nil {
panic(err)
}
return out
} }
out, err := runtime.Decode(codec, buf.Bytes()) expected := &unstructured.UnstructuredList{
if err != nil { Object: map[string]interface{}{"kind": "List", "apiVersion": "v1", "metadata": map[string]interface{}{}, "selfLink": "", "resourceVersion": ""},
t.Fatalf("unexpected error: %v", err) Items: []*unstructured.Unstructured{
fn(&pods.Items[0]),
fn(&pods.Items[1]),
fn(&svc.Items[0]),
},
} }
list, err := meta.ExtractList(out) actualBytes, err := encjson.Marshal(actual[0])
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatal(err)
}
if errs := runtime.DecodeList(list, codec); len(errs) > 0 {
t.Fatalf("unexpected error: %v", errs)
}
if err := meta.SetList(out, list); err != nil {
t.Fatalf("unexpected error: %v", err)
} }
expectedBytes, err := encjson.Marshal(expected)
expected := &api.List{ if err != nil {
Items: []runtime.Object{ t.Fatal(err)
&pods.Items[0],
&pods.Items[1],
&svc.Items[0],
},
} }
if !reflect.DeepEqual(expected, out) { if string(actualBytes) != string(expectedBytes) {
t.Errorf("unexpected output: %#v", out) t.Errorf("unexpected object:\n%s\n%s", expectedBytes, actualBytes)
} }
} }
......
...@@ -39,6 +39,7 @@ import ( ...@@ -39,6 +39,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
) )
...@@ -99,7 +100,7 @@ func NewCmdLabel(f cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -99,7 +100,7 @@ func NewCmdLabel(f cmdutil.Factory, out io.Writer) *cobra.Command {
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs, argAliases := []string{}, []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, kubectl.PrintOptions{ p, err := f.Printer(nil, printers.PrintOptions{
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
......
...@@ -39,6 +39,7 @@ import ( ...@@ -39,6 +39,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/i18n"
) )
...@@ -81,7 +82,7 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -81,7 +82,7 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs, argAliases := []string{}, []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, kubectl.PrintOptions{ p, err := f.Printer(nil, printers.PrintOptions{
ColumnLabels: []string{}, ColumnLabels: []string{},
}) })
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
......
...@@ -56,6 +56,7 @@ go_test( ...@@ -56,6 +56,7 @@ go_test(
"//pkg/kubectl/cmd/testing:go_default_library", "//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/printers:go_default_library",
"//vendor:github.com/spf13/cobra", "//vendor:github.com/spf13/cobra",
"//vendor:github.com/stretchr/testify/assert", "//vendor:github.com/stretchr/testify/assert",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
......
...@@ -22,16 +22,17 @@ import ( ...@@ -22,16 +22,17 @@ import (
"strings" "strings"
"testing" "testing"
"k8s.io/apimachinery/pkg/runtime"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
) )
func TestImageLocal(t *testing.T) { func TestImageLocal(t *testing.T) {
f, tf, _, ns := cmdtesting.NewAPIFactory() f, tf, codec, ns := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
APIRegistry: api.Registry, APIRegistry: api.Registry,
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -47,7 +48,8 @@ func TestImageLocal(t *testing.T) { ...@@ -47,7 +48,8 @@ func TestImageLocal(t *testing.T) {
cmd := NewCmdImage(f, buf, buf) cmd := NewCmdImage(f, buf, buf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", "name")
tf.Printer, _, _ = cmdutil.PrinterForCommand(cmd) mapper, typer := f.Object()
tf.Printer = &printers.NamePrinter{Decoders: []runtime.Decoder{codec}, Typer: typer, Mapper: mapper}
opts := ImageOptions{FilenameOptions: resource.FilenameOptions{ opts := ImageOptions{FilenameOptions: resource.FilenameOptions{
Filenames: []string{"../../../../examples/storage/cassandra/cassandra-controller.yaml"}}, Filenames: []string{"../../../../examples/storage/cassandra/cassandra-controller.yaml"}},
...@@ -63,7 +65,7 @@ func TestImageLocal(t *testing.T) { ...@@ -63,7 +65,7 @@ func TestImageLocal(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
if !strings.Contains(buf.String(), "replicationcontroller/cassandra") { if !strings.Contains(buf.String(), "replicationcontrollers/cassandra") {
t.Errorf("did not set image: %s", buf.String()) t.Errorf("did not set image: %s", buf.String())
} }
} }
...@@ -20,6 +20,7 @@ go_library( ...@@ -20,6 +20,7 @@ go_library(
"//pkg/kubectl:go_default_library", "//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/printers:go_default_library",
"//vendor:github.com/emicklei/go-restful/swagger", "//vendor:github.com/emicklei/go-restful/swagger",
"//vendor:github.com/spf13/cobra", "//vendor:github.com/spf13/cobra",
"//vendor:github.com/spf13/pflag", "//vendor:github.com/spf13/pflag",
......
...@@ -41,6 +41,7 @@ import ( ...@@ -41,6 +41,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
) )
type InternalType struct { type InternalType struct {
...@@ -214,13 +215,15 @@ type TestFactory struct { ...@@ -214,13 +215,15 @@ type TestFactory struct {
Typer runtime.ObjectTyper Typer runtime.ObjectTyper
Client kubectl.RESTClient Client kubectl.RESTClient
UnstructuredClient kubectl.RESTClient UnstructuredClient kubectl.RESTClient
Describer kubectl.Describer Describer printers.Describer
Printer kubectl.ResourcePrinter Printer printers.ResourcePrinter
CommandPrinter printers.ResourcePrinter
Validator validation.Schema Validator validation.Schema
Namespace string Namespace string
ClientConfig *restclient.Config ClientConfig *restclient.Config
Err error Err error
Command string Command string
GenericPrinter bool
ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error) ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error) UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
...@@ -331,11 +334,15 @@ func (f *FakeFactory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (r ...@@ -331,11 +334,15 @@ func (f *FakeFactory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (r
return f.tf.UnstructuredClient, f.tf.Err return f.tf.UnstructuredClient, f.tf.Err
} }
func (f *FakeFactory) Describer(*meta.RESTMapping) (kubectl.Describer, error) { func (f *FakeFactory) Describer(*meta.RESTMapping) (printers.Describer, error) {
return f.tf.Describer, f.tf.Err return f.tf.Describer, f.tf.Err
} }
func (f *FakeFactory) Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) { func (f *FakeFactory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
return f.tf.CommandPrinter, f.tf.GenericPrinter, f.tf.Err
}
func (f *FakeFactory) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error) {
return f.tf.Printer, f.tf.Err return f.tf.Printer, f.tf.Err
} }
...@@ -451,7 +458,7 @@ func (f *FakeFactory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, ob ...@@ -451,7 +458,7 @@ func (f *FakeFactory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, ob
return nil return nil
} }
func (f *FakeFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error) { func (f *FakeFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
return f.tf.Printer, f.tf.Err return f.tf.Printer, f.tf.Err
} }
...@@ -459,8 +466,8 @@ func (f *FakeFactory) NewBuilder() *resource.Builder { ...@@ -459,8 +466,8 @@ func (f *FakeFactory) NewBuilder() *resource.Builder {
return nil return nil
} }
func (f *FakeFactory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions { func (f *FakeFactory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *printers.PrintOptions {
return &kubectl.PrintOptions{} return &printers.PrintOptions{}
} }
func (f *FakeFactory) DefaultResourceFilterFunc() kubectl.Filters { func (f *FakeFactory) DefaultResourceFilterFunc() kubectl.Filters {
...@@ -587,11 +594,15 @@ func (f *fakeAPIFactory) UnstructuredClientForMapping(m *meta.RESTMapping) (reso ...@@ -587,11 +594,15 @@ func (f *fakeAPIFactory) UnstructuredClientForMapping(m *meta.RESTMapping) (reso
return f.tf.UnstructuredClient, f.tf.Err return f.tf.UnstructuredClient, f.tf.Err
} }
func (f *fakeAPIFactory) Describer(*meta.RESTMapping) (kubectl.Describer, error) { func (f *fakeAPIFactory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
return f.tf.CommandPrinter, f.tf.GenericPrinter, f.tf.Err
}
func (f *fakeAPIFactory) Describer(*meta.RESTMapping) (printers.Describer, error) {
return f.tf.Describer, f.tf.Err return f.tf.Describer, f.tf.Err
} }
func (f *fakeAPIFactory) Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) { func (f *fakeAPIFactory) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error) {
return f.tf.Printer, f.tf.Err return f.tf.Printer, f.tf.Err
} }
...@@ -664,7 +675,7 @@ func (f *fakeAPIFactory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, ...@@ -664,7 +675,7 @@ func (f *fakeAPIFactory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper,
return printer.PrintObj(obj, out) return printer.PrintObj(obj, out)
} }
func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error) { func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
return f.tf.Printer, f.tf.Err return f.tf.Printer, f.tf.Err
} }
......
...@@ -38,6 +38,8 @@ go_library( ...@@ -38,6 +38,8 @@ go_library(
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/kubectl:go_default_library", "//pkg/kubectl:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/printers/internalversion:go_default_library",
"//pkg/util/exec:go_default_library", "//pkg/util/exec:go_default_library",
"//pkg/version:go_default_library", "//pkg/version:go_default_library",
"//vendor:github.com/emicklei/go-restful/swagger", "//vendor:github.com/emicklei/go-restful/swagger",
......
...@@ -51,6 +51,7 @@ import ( ...@@ -51,6 +51,7 @@ import (
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
) )
const ( const (
...@@ -136,7 +137,8 @@ type ClientAccessFactory interface { ...@@ -136,7 +137,8 @@ type ClientAccessFactory interface {
// BindExternalFlags adds any flags defined by external projects (not part of pflags) // BindExternalFlags adds any flags defined by external projects (not part of pflags)
BindExternalFlags(flags *pflag.FlagSet) BindExternalFlags(flags *pflag.FlagSet)
DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions // TODO: Break the dependency on cmd here.
DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *printers.PrintOptions
// DefaultResourceFilterFunc returns a collection of FilterFuncs suitable for filtering specific resource types. // DefaultResourceFilterFunc returns a collection of FilterFuncs suitable for filtering specific resource types.
DefaultResourceFilterFunc() kubectl.Filters DefaultResourceFilterFunc() kubectl.Filters
...@@ -144,7 +146,7 @@ type ClientAccessFactory interface { ...@@ -144,7 +146,7 @@ type ClientAccessFactory interface {
SuggestedPodTemplateResources() []schema.GroupResource SuggestedPodTemplateResources() []schema.GroupResource
// Returns a Printer for formatting objects of the given type or an error. // Returns a Printer for formatting objects of the given type or an error.
Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error)
// Pauser marks the object in the info as paused. Currently supported only for Deployments. // Pauser marks the object in the info as paused. Currently supported only for Deployments.
// Returns the patched object in bytes and any error that occured during the encoding or // Returns the patched object in bytes and any error that occured during the encoding or
// in case the object is already paused. // in case the object is already paused.
...@@ -193,7 +195,7 @@ type ObjectMappingFactory interface { ...@@ -193,7 +195,7 @@ type ObjectMappingFactory interface {
// Returns a RESTClient for working with Unstructured objects. // Returns a RESTClient for working with Unstructured objects.
UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error)
// Returns a Describer for displaying the specified RESTMapping type or an error. // Returns a Describer for displaying the specified RESTMapping type or an error.
Describer(mapping *meta.RESTMapping) (kubectl.Describer, error) Describer(mapping *meta.RESTMapping) (printers.Describer, error)
// LogsForObject returns a request for the logs associated with the provided object // LogsForObject returns a request for the logs associated with the provided object
LogsForObject(object, options runtime.Object) (*restclient.Request, error) LogsForObject(object, options runtime.Object) (*restclient.Request, error)
...@@ -211,10 +213,6 @@ type ObjectMappingFactory interface { ...@@ -211,10 +213,6 @@ type ObjectMappingFactory interface {
// AttachablePodForObject returns the pod to which to attach given an object. // AttachablePodForObject returns the pod to which to attach given an object.
AttachablePodForObject(object runtime.Object) (*api.Pod, error) AttachablePodForObject(object runtime.Object) (*api.Pod, error)
// PrinterForMapping returns a printer suitable for displaying the provided resource type.
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error)
// Returns a schema that can validate objects stored on disk. // Returns a schema that can validate objects stored on disk.
Validator(validate bool, cacheDir string) (validation.Schema, error) Validator(validate bool, cacheDir string) (validation.Schema, error)
// SwaggerSchema returns the schema declaration for the provided group version kind. // SwaggerSchema returns the schema declaration for the provided group version kind.
...@@ -224,6 +222,14 @@ type ObjectMappingFactory interface { ...@@ -224,6 +222,14 @@ type ObjectMappingFactory interface {
// BuilderFactory holds the second level of factory methods. These functions depend upon ObjectMappingFactory and ClientAccessFactory methods. // BuilderFactory holds the second level of factory methods. These functions depend upon ObjectMappingFactory and ClientAccessFactory methods.
// Generally they depend upon client mapper functions // Generally they depend upon client mapper functions
type BuilderFactory interface { type BuilderFactory interface {
// PrinterForCommand returns the default printer for the command. It requires that certain options
// are declared on the command (see AddPrinterFlags). Returns a printer, true if the printer is
// generic (is not internal), or an error if a printer could not be found.
// TODO: Break the dependency on cmd here.
PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error)
// PrinterForMapping returns a printer suitable for displaying the provided resource type.
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error)
// PrintObject prints an api object given command line flags to modify the output format // PrintObject prints an api object given command line flags to modify the output format
PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error
// One stop shopping for a Builder // One stop shopping for a Builder
......
...@@ -19,13 +19,16 @@ limitations under the License. ...@@ -19,13 +19,16 @@ limitations under the License.
package util package util
import ( import (
"fmt"
"io" "io"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
) )
type ring2Factory struct { type ring2Factory struct {
...@@ -42,6 +45,54 @@ func NewBuilderFactory(clientAccessFactory ClientAccessFactory, objectMappingFac ...@@ -42,6 +45,54 @@ func NewBuilderFactory(clientAccessFactory ClientAccessFactory, objectMappingFac
return f return f
} }
func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command) (printers.ResourcePrinter, bool, error) {
mapper, typer := f.objectMappingFactory.Object()
// TODO: used by the custom column implementation and the name implementation, break this dependency
decoders := []runtime.Decoder{f.clientAccessFactory.Decoder(true), unstructured.UnstructuredJSONScheme}
return PrinterForCommand(cmd, mapper, typer, decoders)
}
func (f *ring2Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
printer, generic, err := f.PrinterForCommand(cmd)
if err != nil {
return nil, err
}
// Make sure we output versioned data for generic printers
if generic {
if mapping == nil {
return nil, fmt.Errorf("no serialization format found")
}
version := mapping.GroupVersionKind.GroupVersion()
if version.Empty() {
return nil, fmt.Errorf("no serialization format found")
}
printer = printers.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
} else {
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
if err != nil {
columnLabel = []string{}
}
printer, err = f.clientAccessFactory.Printer(mapping, printers.PrintOptions{
NoHeaders: GetFlagBool(cmd, "no-headers"),
WithNamespace: withNamespace,
Wide: GetWideFlag(cmd),
ShowAll: GetFlagBool(cmd, "show-all"),
ShowLabels: GetFlagBool(cmd, "show-labels"),
AbsoluteTimestamps: isWatch(cmd),
ColumnLabels: columnLabel,
})
if err != nil {
return nil, err
}
printer = maybeWrapSortingPrinter(cmd, printer)
}
return printer, nil
}
func (f *ring2Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error { func (f *ring2Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error {
// try to get a typed object // try to get a typed object
_, typer := f.objectMappingFactory.Object() _, typer := f.objectMappingFactory.Object()
...@@ -66,7 +117,7 @@ func (f *ring2Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, o ...@@ -66,7 +117,7 @@ func (f *ring2Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, o
return err return err
} }
printer, err := f.objectMappingFactory.PrinterForMapping(cmd, mapping, false) printer, err := f.PrinterForMapping(cmd, mapping, false)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -49,6 +49,8 @@ import ( ...@@ -49,6 +49,8 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
) )
type ring0Factory struct { type ring0Factory struct {
...@@ -360,12 +362,12 @@ func (f *ring0Factory) BindExternalFlags(flags *pflag.FlagSet) { ...@@ -360,12 +362,12 @@ func (f *ring0Factory) BindExternalFlags(flags *pflag.FlagSet) {
flags.AddGoFlagSet(flag.CommandLine) flags.AddGoFlagSet(flag.CommandLine)
} }
func (f *ring0Factory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions { func (f *ring0Factory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *printers.PrintOptions {
columnLabel, err := cmd.Flags().GetStringSlice("label-columns") columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
if err != nil { if err != nil {
columnLabel = []string{} columnLabel = []string{}
} }
opts := &kubectl.PrintOptions{ opts := &printers.PrintOptions{
NoHeaders: GetFlagBool(cmd, "no-headers"), NoHeaders: GetFlagBool(cmd, "no-headers"),
WithNamespace: withNamespace, WithNamespace: withNamespace,
Wide: GetWideFlag(cmd), Wide: GetWideFlag(cmd),
...@@ -392,8 +394,10 @@ func (f *ring0Factory) SuggestedPodTemplateResources() []schema.GroupResource { ...@@ -392,8 +394,10 @@ func (f *ring0Factory) SuggestedPodTemplateResources() []schema.GroupResource {
} }
} }
func (f *ring0Factory) Printer(mapping *meta.RESTMapping, options kubectl.PrintOptions) (kubectl.ResourcePrinter, error) { func (f *ring0Factory) Printer(mapping *meta.RESTMapping, options printers.PrintOptions) (printers.ResourcePrinter, error) {
return kubectl.NewHumanReadablePrinter(options), nil p := printers.NewHumanReadablePrinter(options)
printersinternal.AddHandlers(p)
return p, nil
} }
func (f *ring0Factory) Pauser(info *resource.Info) ([]byte, error) { func (f *ring0Factory) Pauser(info *resource.Info) ([]byte, error) {
......
...@@ -27,7 +27,6 @@ import ( ...@@ -27,7 +27,6 @@ import (
"time" "time"
"github.com/emicklei/go-restful/swagger" "github.com/emicklei/go-restful/swagger"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
...@@ -48,6 +47,8 @@ import ( ...@@ -48,6 +47,8 @@ import (
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
) )
type ring1Factory struct { type ring1Factory struct {
...@@ -58,10 +59,12 @@ func NewObjectMappingFactory(clientAccessFactory ClientAccessFactory) ObjectMapp ...@@ -58,10 +59,12 @@ func NewObjectMappingFactory(clientAccessFactory ClientAccessFactory) ObjectMapp
f := &ring1Factory{ f := &ring1Factory{
clientAccessFactory: clientAccessFactory, clientAccessFactory: clientAccessFactory,
} }
return f return f
} }
// TODO: This method should return an error now that it can fail. Alternatively, it needs to
// return lazy implementations of mapper and typer that don't hit the wire until they are
// invoked.
func (f *ring1Factory) Object() (meta.RESTMapper, runtime.ObjectTyper) { func (f *ring1Factory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
mapper := api.Registry.RESTMapper() mapper := api.Registry.RESTMapper()
discoveryClient, err := f.clientAccessFactory.DiscoveryClient() discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
...@@ -143,7 +146,7 @@ func (f *ring1Factory) UnstructuredClientForMapping(mapping *meta.RESTMapping) ( ...@@ -143,7 +146,7 @@ func (f *ring1Factory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (
return restclient.RESTClientFor(cfg) return restclient.RESTClientFor(cfg)
} }
func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer, error) { func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (printers.Describer, error) {
mappingVersion := mapping.GroupVersionKind.GroupVersion() mappingVersion := mapping.GroupVersionKind.GroupVersion()
if mapping.GroupVersionKind.Group == federation.GroupName { if mapping.GroupVersionKind.Group == federation.GroupName {
fedClientSet, err := f.clientAccessFactory.FederationClientSetForVersion(&mappingVersion) fedClientSet, err := f.clientAccessFactory.FederationClientSetForVersion(&mappingVersion)
...@@ -151,7 +154,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer, ...@@ -151,7 +154,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer,
return nil, err return nil, err
} }
if mapping.GroupVersionKind.Kind == "Cluster" { if mapping.GroupVersionKind.Kind == "Cluster" {
return &kubectl.ClusterDescriber{Interface: fedClientSet}, nil return &printersinternal.ClusterDescriber{Interface: fedClientSet}, nil
} }
} }
...@@ -166,7 +169,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer, ...@@ -166,7 +169,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer,
} }
// try to get a describer // try to get a describer
if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientset); ok { if describer, ok := printersinternal.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientset); ok {
return describer, nil return describer, nil
} }
// if this is a kind we don't have a describer for yet, go generic if possible // if this is a kind we don't have a describer for yet, go generic if possible
...@@ -178,7 +181,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer, ...@@ -178,7 +181,7 @@ func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer,
} }
// helper function to make a generic describer, or return an error // helper function to make a generic describer, or return an error
func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RESTMapping) (kubectl.Describer, error) { func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RESTMapping) (printers.Describer, error) {
clientConfig, err := clientAccessFactory.ClientConfig() clientConfig, err := clientAccessFactory.ClientConfig()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -202,7 +205,7 @@ func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RES ...@@ -202,7 +205,7 @@ func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RES
} }
eventsClient := clientSet.Core() eventsClient := clientSet.Core()
return kubectl.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil return printersinternal.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil
} }
func (f *ring1Factory) LogsForObject(object, options runtime.Object) (*restclient.Request, error) { func (f *ring1Factory) LogsForObject(object, options runtime.Object) (*restclient.Request, error) {
...@@ -361,48 +364,6 @@ func (f *ring1Factory) AttachablePodForObject(object runtime.Object) (*api.Pod, ...@@ -361,48 +364,6 @@ func (f *ring1Factory) AttachablePodForObject(object runtime.Object) (*api.Pod,
return pod, err return pod, err
} }
func (f *ring1Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (kubectl.ResourcePrinter, error) {
printer, generic, err := PrinterForCommand(cmd)
if err != nil {
return nil, err
}
// Make sure we output versioned data for generic printers
if generic {
if mapping == nil {
return nil, fmt.Errorf("no serialization format found")
}
version := mapping.GroupVersionKind.GroupVersion()
if version.Empty() {
return nil, fmt.Errorf("no serialization format found")
}
printer = kubectl.NewVersionedPrinter(printer, mapping.ObjectConvertor, version, mapping.GroupVersionKind.GroupVersion())
} else {
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
if err != nil {
columnLabel = []string{}
}
printer, err = f.clientAccessFactory.Printer(mapping, kubectl.PrintOptions{
NoHeaders: GetFlagBool(cmd, "no-headers"),
WithNamespace: withNamespace,
Wide: GetWideFlag(cmd),
ShowAll: GetFlagBool(cmd, "show-all"),
ShowLabels: GetFlagBool(cmd, "show-labels"),
AbsoluteTimestamps: isWatch(cmd),
ColumnLabels: columnLabel,
})
if err != nil {
return nil, err
}
printer = maybeWrapSortingPrinter(cmd, printer)
}
return printer, nil
}
func (f *ring1Factory) Validator(validate bool, cacheDir string) (validation.Schema, error) { func (f *ring1Factory) Validator(validate bool, cacheDir string) (validation.Schema, error) {
if validate { if validate {
discovery, err := f.clientAccessFactory.DiscoveryClient() discovery, err := f.clientAccessFactory.DiscoveryClient()
......
...@@ -47,6 +47,7 @@ import ( ...@@ -47,6 +47,7 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
utilexec "k8s.io/kubernetes/pkg/util/exec" utilexec "k8s.io/kubernetes/pkg/util/exec"
) )
...@@ -672,7 +673,7 @@ func MustPrintWithKinds(objs []runtime.Object, infos []*resource.Info, sorter *k ...@@ -672,7 +673,7 @@ func MustPrintWithKinds(objs []runtime.Object, infos []*resource.Info, sorter *k
// FilterResourceList receives a list of runtime objects. // FilterResourceList receives a list of runtime objects.
// If any objects are filtered, that number is returned along with a modified list. // If any objects are filtered, that number is returned along with a modified list.
func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterOpts *kubectl.PrintOptions) (int, []runtime.Object, error) { func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterOpts *printers.PrintOptions) (int, []runtime.Object, error) {
items, err := meta.ExtractList(obj) items, err := meta.ExtractList(obj)
if err != nil { if err != nil {
return 0, []runtime.Object{obj}, utilerrors.NewAggregate([]error{err}) return 0, []runtime.Object{obj}, utilerrors.NewAggregate([]error{err})
...@@ -697,7 +698,7 @@ func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterO ...@@ -697,7 +698,7 @@ func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterO
return filterCount, list, nil return filterCount, list, nil
} }
func PrintFilterCount(hiddenObjNum int, resource string, options *kubectl.PrintOptions) { func PrintFilterCount(hiddenObjNum int, resource string, options *printers.PrintOptions) {
if !options.NoHeaders && !options.ShowAll && hiddenObjNum > 0 { if !options.NoHeaders && !options.ShowAll && hiddenObjNum > 0 {
glog.V(2).Infof(" info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", hiddenObjNum, resource) glog.V(2).Infof(" info: %d completed object(s) was(were) not shown in %s list. Pass --show-all to see all objects.\n\n", hiddenObjNum, resource)
} }
......
...@@ -22,8 +22,10 @@ import ( ...@@ -22,8 +22,10 @@ import (
"strings" "strings"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/printers"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -105,7 +107,7 @@ func ValidateOutputArgs(cmd *cobra.Command) error { ...@@ -105,7 +107,7 @@ func ValidateOutputArgs(cmd *cobra.Command) error {
// PrinterForCommand returns the default printer for this command. // PrinterForCommand returns the default printer for this command.
// Requires that printer flags have been added to cmd (see AddPrinterFlags). // Requires that printer flags have been added to cmd (see AddPrinterFlags).
func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error) { func PrinterForCommand(cmd *cobra.Command, mapper meta.RESTMapper, typer runtime.ObjectTyper, decoders []runtime.Decoder) (printers.ResourcePrinter, bool, error) {
outputFormat := GetFlagString(cmd, "output") outputFormat := GetFlagString(cmd, "output")
// templates are logically optional for specifying a format. // templates are logically optional for specifying a format.
...@@ -131,7 +133,10 @@ func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error ...@@ -131,7 +133,10 @@ func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error
if cmd.Flags().Lookup("allow-missing-template-keys") != nil { if cmd.Flags().Lookup("allow-missing-template-keys") != nil {
allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys") allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys")
} }
printer, generic, err := kubectl.GetPrinter(outputFormat, templateFile, GetFlagBool(cmd, "no-headers"), allowMissingTemplateKeys) printer, generic, err := printers.GetStandardPrinter(
outputFormat, templateFile, GetFlagBool(cmd, "no-headers"), allowMissingTemplateKeys,
mapper, typer, decoders,
)
if err != nil { if err != nil {
return nil, generic, err return nil, generic, err
} }
...@@ -144,7 +149,7 @@ func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error ...@@ -144,7 +149,7 @@ func PrinterForCommand(cmd *cobra.Command) (kubectl.ResourcePrinter, bool, error
// object passed is non-generic, it attempts to print the object using a HumanReadablePrinter. // object passed is non-generic, it attempts to print the object using a HumanReadablePrinter.
// Requires that printer flags have been added to cmd (see AddPrinterFlags). // Requires that printer flags have been added to cmd (see AddPrinterFlags).
func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Factory, out io.Writer) error { func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Factory, out io.Writer) error {
printer, generic, err := PrinterForCommand(cmd) printer, generic, err := f.PrinterForCommand(cmd)
if err != nil { if err != nil {
return err return err
} }
...@@ -157,7 +162,7 @@ func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Fact ...@@ -157,7 +162,7 @@ func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Fact
return printer.PrintObj(info.Object, out) return printer.PrintObj(info.Object, out)
} }
func maybeWrapSortingPrinter(cmd *cobra.Command, printer kubectl.ResourcePrinter) kubectl.ResourcePrinter { func maybeWrapSortingPrinter(cmd *cobra.Command, printer printers.ResourcePrinter) printers.ResourcePrinter {
sorting, err := cmd.Flags().GetString("sort-by") sorting, err := cmd.Flags().GetString("sort-by")
if err != nil { if err != nil {
// error can happen on missing flag or bad flag type. In either case, this command didn't intent to sort // error can happen on missing flag or bad flag type. In either case, this command didn't intent to sort
......
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"text/tabwriter"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
...@@ -30,6 +31,7 @@ import ( ...@@ -30,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
sliceutil "k8s.io/kubernetes/pkg/util/slice" sliceutil "k8s.io/kubernetes/pkg/util/slice"
) )
...@@ -55,6 +57,7 @@ type DeploymentHistoryViewer struct { ...@@ -55,6 +57,7 @@ type DeploymentHistoryViewer struct {
} }
// ViewHistory returns a revision-to-replicaset map as the revision history of a deployment // ViewHistory returns a revision-to-replicaset map as the revision history of a deployment
// TODO: this should be a describer
func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) { func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) {
versionedClient := versionedClientsetForDeployment(h.c) versionedClient := versionedClientsetForDeployment(h.c)
deployment, err := versionedClient.Extensions().Deployments(namespace).Get(name, metav1.GetOptions{}) deployment, err := versionedClient.Extensions().Deployments(namespace).Get(name, metav1.GetOptions{})
...@@ -101,7 +104,7 @@ func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision i ...@@ -101,7 +104,7 @@ func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision i
if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil { if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil {
return "", fmt.Errorf("failed to convert podtemplate, %v", err) return "", fmt.Errorf("failed to convert podtemplate, %v", err)
} }
DescribePodTemplate(internalTemplate, buf) printersinternal.DescribePodTemplate(internalTemplate, buf)
return buf.String(), nil return buf.String(), nil
} }
...@@ -126,6 +129,22 @@ func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision i ...@@ -126,6 +129,22 @@ func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision i
}) })
} }
// TODO: copied here until this becomes a describer
func tabbedString(f func(io.Writer) error) (string, error) {
out := new(tabwriter.Writer)
buf := &bytes.Buffer{}
out.Init(buf, 0, 8, 1, '\t', 0)
err := f(out)
if err != nil {
return "", err
}
out.Flush()
str := string(buf.String())
return str, nil
}
// getChangeCause returns the change-cause annotation of the input object // getChangeCause returns the change-cause annotation of the input object
func getChangeCause(obj runtime.Object) string { func getChangeCause(obj runtime.Object) string {
accessor, err := meta.Accessor(obj) accessor, err := meta.Accessor(obj)
......
...@@ -24,7 +24,6 @@ import ( ...@@ -24,7 +24,6 @@ import (
"strings" "strings"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api"
) )
const ( const (
...@@ -35,18 +34,6 @@ type NamespaceInfo struct { ...@@ -35,18 +34,6 @@ type NamespaceInfo struct {
Namespace string Namespace string
} }
func listOfImages(spec *api.PodSpec) []string {
images := make([]string, 0, len(spec.Containers))
for _, container := range spec.Containers {
images = append(images, container.Image)
}
return images
}
func makeImageList(spec *api.PodSpec) string {
return strings.Join(listOfImages(spec), ",")
}
// ResourceShortcuts represents a structure that holds the information how to // ResourceShortcuts represents a structure that holds the information how to
// transition from resource's shortcut to its full name. // transition from resource's shortcut to its full name.
type ResourceShortcuts struct { type ResourceShortcuts struct {
......
...@@ -18,7 +18,7 @@ go_library( ...@@ -18,7 +18,7 @@ go_library(
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/validation:go_default_library", "//pkg/api/validation:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/kubectl:go_default_library", "//pkg/printers:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/resource", "//vendor:k8s.io/apimachinery/pkg/api/resource",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/labels", "//vendor:k8s.io/apimachinery/pkg/labels",
......
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metricsapi "k8s.io/heapster/metrics/apis/metrics/v1alpha1" metricsapi "k8s.io/heapster/metrics/apis/metrics/v1alpha1"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/printers"
) )
var ( var (
...@@ -55,7 +55,7 @@ func (printer *TopCmdPrinter) PrintNodeMetrics(metrics []metricsapi.NodeMetrics, ...@@ -55,7 +55,7 @@ func (printer *TopCmdPrinter) PrintNodeMetrics(metrics []metricsapi.NodeMetrics,
if len(metrics) == 0 { if len(metrics) == 0 {
return nil return nil
} }
w := kubectl.GetNewTabWriter(printer.out) w := printers.GetNewTabWriter(printer.out)
defer w.Flush() defer w.Flush()
printColumnNames(w, NodeColumns) printColumnNames(w, NodeColumns)
...@@ -78,7 +78,7 @@ func (printer *TopCmdPrinter) PrintPodMetrics(metrics []metricsapi.PodMetrics, p ...@@ -78,7 +78,7 @@ func (printer *TopCmdPrinter) PrintPodMetrics(metrics []metricsapi.PodMetrics, p
if len(metrics) == 0 { if len(metrics) == 0 {
return nil return nil
} }
w := kubectl.GetNewTabWriter(printer.out) w := printers.GetNewTabWriter(printer.out)
defer w.Flush() defer w.Flush()
if withNamespace { if withNamespace {
......
...@@ -20,12 +20,13 @@ import ( ...@@ -20,12 +20,13 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/printers"
) )
// FilterFunc is a function that knows how to filter a specific resource kind. // FilterFunc is a function that knows how to filter a specific resource kind.
// It receives a generic runtime.Object which must be type-checked by the function. // It receives a generic runtime.Object which must be type-checked by the function.
// Returns a boolean value true if a resource is filtered, or false otherwise. // Returns a boolean value true if a resource is filtered, or false otherwise.
type FilterFunc func(runtime.Object, PrintOptions) bool type FilterFunc func(runtime.Object, printers.PrintOptions) bool
// Filters is a collection of filter funcs // Filters is a collection of filter funcs
type Filters []FilterFunc type Filters []FilterFunc
...@@ -38,7 +39,7 @@ func NewResourceFilter() Filters { ...@@ -38,7 +39,7 @@ func NewResourceFilter() Filters {
// filterPods returns true if a pod should be skipped. // filterPods returns true if a pod should be skipped.
// defaults to true for terminated pods // defaults to true for terminated pods
func filterPods(obj runtime.Object, options PrintOptions) bool { func filterPods(obj runtime.Object, options printers.PrintOptions) bool {
switch p := obj.(type) { switch p := obj.(type) {
case *v1.Pod: case *v1.Pod:
reason := string(p.Status.Phase) reason := string(p.Status.Phase)
...@@ -57,7 +58,7 @@ func filterPods(obj runtime.Object, options PrintOptions) bool { ...@@ -57,7 +58,7 @@ func filterPods(obj runtime.Object, options PrintOptions) bool {
} }
// Filter loops through a collection of FilterFuncs until it finds one that can filter the given resource // Filter loops through a collection of FilterFuncs until it finds one that can filter the given resource
func (f Filters) Filter(obj runtime.Object, opts *PrintOptions) (bool, error) { func (f Filters) Filter(obj runtime.Object, opts *printers.PrintOptions) (bool, error) {
// check if the object is unstructured. If so, let's attempt to convert it to a type we can understand // check if the object is unstructured. If so, let's attempt to convert it to a type we can understand
// before apply filter func. // before apply filter func.
obj, _ = DecodeUnknownObject(obj) obj, _ = DecodeUnknownObject(obj)
......
...@@ -33,6 +33,7 @@ import ( ...@@ -33,6 +33,7 @@ import (
externalextensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" externalextensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
sliceutil "k8s.io/kubernetes/pkg/util/slice" sliceutil "k8s.io/kubernetes/pkg/util/slice"
) )
...@@ -170,7 +171,7 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe ...@@ -170,7 +171,7 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe
if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil { if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil {
return "", fmt.Errorf("failed to convert podtemplate, %v", err) return "", fmt.Errorf("failed to convert podtemplate, %v", err)
} }
DescribePodTemplate(internalTemplate, buf) printersinternal.DescribePodTemplate(internalTemplate, buf)
return buf.String(), nil return buf.String(), nil
} }
...@@ -188,6 +189,6 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe ...@@ -188,6 +189,6 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe
if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil { if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil {
return "", fmt.Errorf("failed to convert podtemplate, %v", err) return "", fmt.Errorf("failed to convert podtemplate, %v", err)
} }
DescribePodTemplate(internalTemplate, buf) printersinternal.DescribePodTemplate(internalTemplate, buf)
return buf.String(), nil return buf.String(), nil
} }
/*
Copyright 2014 The Kubernetes Authors.
Licensed 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 kubectl
import (
"sort"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/kubelet/qos"
)
type SortableResourceNames []api.ResourceName
func (list SortableResourceNames) Len() int {
return len(list)
}
func (list SortableResourceNames) Swap(i, j int) {
list[i], list[j] = list[j], list[i]
}
func (list SortableResourceNames) Less(i, j int) bool {
return list[i] < list[j]
}
// SortedResourceNames returns the sorted resource names of a resource list.
func SortedResourceNames(list api.ResourceList) []api.ResourceName {
resources := make([]api.ResourceName, 0, len(list))
for res := range list {
resources = append(resources, res)
}
sort.Sort(SortableResourceNames(resources))
return resources
}
type SortableResourceQuotas []api.ResourceQuota
func (list SortableResourceQuotas) Len() int {
return len(list)
}
func (list SortableResourceQuotas) Swap(i, j int) {
list[i], list[j] = list[j], list[i]
}
func (list SortableResourceQuotas) Less(i, j int) bool {
return list[i].Name < list[j].Name
}
type SortableVolumeMounts []api.VolumeMount
func (list SortableVolumeMounts) Len() int {
return len(list)
}
func (list SortableVolumeMounts) Swap(i, j int) {
list[i], list[j] = list[j], list[i]
}
func (list SortableVolumeMounts) Less(i, j int) bool {
return list[i].MountPath < list[j].MountPath
}
// SortedQoSResourceNames returns the sorted resource names of a QoS list.
func SortedQoSResourceNames(list qos.QOSList) []api.ResourceName {
resources := make([]api.ResourceName, 0, len(list))
for res := range list {
resources = append(resources, api.ResourceName(res))
}
sort.Sort(SortableResourceNames(resources))
return resources
}
...@@ -31,13 +31,14 @@ import ( ...@@ -31,13 +31,14 @@ import (
"k8s.io/client-go/util/integer" "k8s.io/client-go/util/integer"
"k8s.io/client-go/util/jsonpath" "k8s.io/client-go/util/jsonpath"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/printers"
) )
// Sorting printer sorts list types before delegating to another printer. // Sorting printer sorts list types before delegating to another printer.
// Non-list types are simply passed through // Non-list types are simply passed through
type SortingPrinter struct { type SortingPrinter struct {
SortField string SortField string
Delegate ResourcePrinter Delegate printers.ResourcePrinter
Decoder runtime.Decoder Decoder runtime.Decoder
} }
...@@ -101,7 +102,7 @@ func SortObjects(decoder runtime.Decoder, objs []runtime.Object, fieldInput stri ...@@ -101,7 +102,7 @@ func SortObjects(decoder runtime.Decoder, objs []runtime.Object, fieldInput stri
} }
} }
field, err := massageJSONPath(fieldInput) field, err := printers.RelaxedJSONPathExpression(fieldInput)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
{
"Rules": [
{
"SelectorRegexp": "k8s[.]io/kubernetes/pkg/(api$|apis/)",
"ForbiddenPrefixes": [
"k8s.io/kubernetes/pkg/printers"
]
}
]
}
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"common.go",
"customcolumn.go",
"humanreadable.go",
"interface.go",
"json.go",
"jsonpath.go",
"name.go",
"printers.go",
"tabwriter.go",
"template.go",
"versioned.go",
],
tags = ["automanaged"],
deps = [
"//vendor:github.com/ghodss/yaml",
"//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/api/meta",
"//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/client-go/util/jsonpath",
],
)
go_test(
name = "go_default_xtest",
srcs = ["customcolumn_test.go"],
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/printers:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/runtime",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//pkg/printers/internalversion:all-srcs",
],
tags = ["automanaged"],
)
/*
Copyright 2014 The Kubernetes Authors.
Licensed 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 printers
import (
"fmt"
"time"
)
func ShortHumanDuration(d time.Duration) string {
// Allow deviation no more than 2 seconds(excluded) to tolerate machine time
// inconsistence, it can be considered as almost now.
if seconds := int(d.Seconds()); seconds < -1 {
return fmt.Sprintf("<invalid>")
} else if seconds < 0 {
return fmt.Sprintf("0s")
} else if seconds < 60 {
return fmt.Sprintf("%ds", seconds)
} else if minutes := int(d.Minutes()); minutes < 60 {
return fmt.Sprintf("%dm", minutes)
} else if hours := int(d.Hours()); hours < 24 {
return fmt.Sprintf("%dh", hours)
} else if hours < 24*364 {
return fmt.Sprintf("%dd", hours/24)
}
return fmt.Sprintf("%dy", int(d.Hours()/24/365))
}
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package kubectl package printers
import ( import (
"bufio" "bufio"
...@@ -41,14 +41,14 @@ const ( ...@@ -41,14 +41,14 @@ const (
var jsonRegexp = regexp.MustCompile("^\\{\\.?([^{}]+)\\}$|^\\.?([^{}]+)$") var jsonRegexp = regexp.MustCompile("^\\{\\.?([^{}]+)\\}$|^\\.?([^{}]+)$")
// MassageJSONPath attempts to be flexible with JSONPath expressions, it accepts: // RelaxedJSONPathExpression attempts to be flexible with JSONPath expressions, it accepts:
// * metadata.name (no leading '.' or curly brances '{...}' // * metadata.name (no leading '.' or curly brances '{...}'
// * {metadata.name} (no leading '.') // * {metadata.name} (no leading '.')
// * .metadata.name (no curly braces '{...}') // * .metadata.name (no curly braces '{...}')
// * {.metadata.name} (complete expression) // * {.metadata.name} (complete expression)
// And transforms them all into a valid jsonpat expression: // And transforms them all into a valid jsonpath expression:
// {.metadata.name} // {.metadata.name}
func massageJSONPath(pathExpression string) (string, error) { func RelaxedJSONPathExpression(pathExpression string) (string, error) {
if len(pathExpression) == 0 { if len(pathExpression) == 0 {
return pathExpression, nil return pathExpression, nil
} }
...@@ -84,7 +84,7 @@ func NewCustomColumnsPrinterFromSpec(spec string, decoder runtime.Decoder, noHea ...@@ -84,7 +84,7 @@ func NewCustomColumnsPrinterFromSpec(spec string, decoder runtime.Decoder, noHea
if len(colSpec) != 2 { if len(colSpec) != 2 {
return nil, fmt.Errorf("unexpected custom-columns spec: %s, expected <header>:<json-path-expr>", parts[ix]) return nil, fmt.Errorf("unexpected custom-columns spec: %s, expected <header>:<json-path-expr>", parts[ix])
} }
spec, err := massageJSONPath(colSpec[1]) spec, err := RelaxedJSONPathExpression(colSpec[1])
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -126,7 +126,7 @@ func NewCustomColumnsPrinterFromTemplate(templateReader io.Reader, decoder runti ...@@ -126,7 +126,7 @@ func NewCustomColumnsPrinterFromTemplate(templateReader io.Reader, decoder runti
columns := make([]Column, len(headers)) columns := make([]Column, len(headers))
for ix := range headers { for ix := range headers {
spec, err := massageJSONPath(specs[ix]) spec, err := RelaxedJSONPathExpression(specs[ix])
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package kubectl package printers_test
import ( import (
"bytes" "bytes"
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/printers"
) )
func TestMassageJSONPath(t *testing.T) { func TestMassageJSONPath(t *testing.T) {
...@@ -45,7 +46,7 @@ func TestMassageJSONPath(t *testing.T) { ...@@ -45,7 +46,7 @@ func TestMassageJSONPath(t *testing.T) {
{input: "{{foo.bar}", expectErr: true}, {input: "{{foo.bar}", expectErr: true},
} }
for _, test := range tests { for _, test := range tests {
output, err := massageJSONPath(test.input) output, err := printers.RelaxedJSONPathExpression(test.input)
if err != nil && !test.expectErr { if err != nil && !test.expectErr {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
continue continue
...@@ -65,7 +66,7 @@ func TestMassageJSONPath(t *testing.T) { ...@@ -65,7 +66,7 @@ func TestMassageJSONPath(t *testing.T) {
func TestNewColumnPrinterFromSpec(t *testing.T) { func TestNewColumnPrinterFromSpec(t *testing.T) {
tests := []struct { tests := []struct {
spec string spec string
expectedColumns []Column expectedColumns []printers.Column
expectErr bool expectErr bool
name string name string
noHeaders bool noHeaders bool
...@@ -93,7 +94,7 @@ func TestNewColumnPrinterFromSpec(t *testing.T) { ...@@ -93,7 +94,7 @@ func TestNewColumnPrinterFromSpec(t *testing.T) {
{ {
spec: "NAME:metadata.name,API_VERSION:apiVersion", spec: "NAME:metadata.name,API_VERSION:apiVersion",
name: "ok", name: "ok",
expectedColumns: []Column{ expectedColumns: []printers.Column{
{ {
Header: "NAME", Header: "NAME",
FieldSpec: "{.metadata.name}", FieldSpec: "{.metadata.name}",
...@@ -111,7 +112,7 @@ func TestNewColumnPrinterFromSpec(t *testing.T) { ...@@ -111,7 +112,7 @@ func TestNewColumnPrinterFromSpec(t *testing.T) {
}, },
} }
for _, test := range tests { for _, test := range tests {
printer, err := NewCustomColumnsPrinterFromSpec(test.spec, api.Codecs.UniversalDecoder(), test.noHeaders) printer, err := printers.NewCustomColumnsPrinterFromSpec(test.spec, api.Codecs.UniversalDecoder(), test.noHeaders)
if test.expectErr { if test.expectErr {
if err == nil { if err == nil {
t.Errorf("[%s] unexpected non-error", test.name) t.Errorf("[%s] unexpected non-error", test.name)
...@@ -141,6 +142,15 @@ func TestNewColumnPrinterFromSpec(t *testing.T) { ...@@ -141,6 +142,15 @@ func TestNewColumnPrinterFromSpec(t *testing.T) {
} }
} }
func contains(arr []string, s string) bool {
for i := range arr {
if arr[i] == s {
return true
}
}
return false
}
const exampleTemplateOne = `NAME API_VERSION const exampleTemplateOne = `NAME API_VERSION
{metadata.name} {apiVersion}` {metadata.name} {apiVersion}`
...@@ -150,7 +160,7 @@ const exampleTemplateTwo = `NAME API_VERSION ...@@ -150,7 +160,7 @@ const exampleTemplateTwo = `NAME API_VERSION
func TestNewColumnPrinterFromTemplate(t *testing.T) { func TestNewColumnPrinterFromTemplate(t *testing.T) {
tests := []struct { tests := []struct {
spec string spec string
expectedColumns []Column expectedColumns []printers.Column
expectErr bool expectErr bool
name string name string
}{ }{
...@@ -177,7 +187,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) { ...@@ -177,7 +187,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) {
{ {
spec: exampleTemplateOne, spec: exampleTemplateOne,
name: "ok", name: "ok",
expectedColumns: []Column{ expectedColumns: []printers.Column{
{ {
Header: "NAME", Header: "NAME",
FieldSpec: "{.metadata.name}", FieldSpec: "{.metadata.name}",
...@@ -191,7 +201,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) { ...@@ -191,7 +201,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) {
{ {
spec: exampleTemplateTwo, spec: exampleTemplateTwo,
name: "ok-2", name: "ok-2",
expectedColumns: []Column{ expectedColumns: []printers.Column{
{ {
Header: "NAME", Header: "NAME",
FieldSpec: "{.metadata.name}", FieldSpec: "{.metadata.name}",
...@@ -205,7 +215,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) { ...@@ -205,7 +215,7 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) {
} }
for _, test := range tests { for _, test := range tests {
reader := bytes.NewBufferString(test.spec) reader := bytes.NewBufferString(test.spec)
printer, err := NewCustomColumnsPrinterFromTemplate(reader, api.Codecs.UniversalDecoder()) printer, err := printers.NewCustomColumnsPrinterFromTemplate(reader, api.Codecs.UniversalDecoder())
if test.expectErr { if test.expectErr {
if err == nil { if err == nil {
t.Errorf("[%s] unexpected non-error", test.name) t.Errorf("[%s] unexpected non-error", test.name)
...@@ -226,12 +236,12 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) { ...@@ -226,12 +236,12 @@ func TestNewColumnPrinterFromTemplate(t *testing.T) {
func TestColumnPrint(t *testing.T) { func TestColumnPrint(t *testing.T) {
tests := []struct { tests := []struct {
columns []Column columns []printers.Column
obj runtime.Object obj runtime.Object
expectedOutput string expectedOutput string
}{ }{
{ {
columns: []Column{ columns: []printers.Column{
{ {
Header: "NAME", Header: "NAME",
FieldSpec: "{.metadata.name}", FieldSpec: "{.metadata.name}",
...@@ -243,7 +253,7 @@ foo ...@@ -243,7 +253,7 @@ foo
`, `,
}, },
{ {
columns: []Column{ columns: []printers.Column{
{ {
Header: "NAME", Header: "NAME",
FieldSpec: "{.metadata.name}", FieldSpec: "{.metadata.name}",
...@@ -261,7 +271,7 @@ bar ...@@ -261,7 +271,7 @@ bar
`, `,
}, },
{ {
columns: []Column{ columns: []printers.Column{
{ {
Header: "NAME", Header: "NAME",
FieldSpec: "{.metadata.name}", FieldSpec: "{.metadata.name}",
...@@ -279,7 +289,7 @@ foo baz ...@@ -279,7 +289,7 @@ foo baz
} }
for _, test := range tests { for _, test := range tests {
printer := &CustomColumnsPrinter{ printer := &printers.CustomColumnsPrinter{
Columns: test.columns, Columns: test.columns,
Decoder: api.Codecs.UniversalDecoder(), Decoder: api.Codecs.UniversalDecoder(),
} }
......
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 printers
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
)
// ResourcePrinter is an interface that knows how to print runtime objects.
type ResourcePrinter interface {
// Print receives a runtime object, formats it and prints it to a writer.
PrintObj(runtime.Object, io.Writer) error
HandledResources() []string
//Can be used to print out warning/clarifications if needed
//after all objects were printed
AfterPrint(io.Writer, string) error
}
// ResourcePrinterFunc is a function that can print objects
type ResourcePrinterFunc func(runtime.Object, io.Writer) error
// PrintObj implements ResourcePrinter
func (fn ResourcePrinterFunc) PrintObj(obj runtime.Object, w io.Writer) error {
return fn(obj, w)
}
// TODO: implement HandledResources()
func (fn ResourcePrinterFunc) HandledResources() []string {
return []string{}
}
func (fn ResourcePrinterFunc) AfterPrint(io.Writer, string) error {
return nil
}
type PrintOptions struct {
NoHeaders bool
WithNamespace bool
WithKind bool
Wide bool
ShowAll bool
ShowLabels bool
AbsoluteTimestamps bool
Kind string
ColumnLabels []string
}
// Describer generates output for the named resource or an error
// if the output could not be generated. Implementers typically
// abstract the retrieval of the named object from a remote server.
type Describer interface {
Describe(namespace, name string, describerSettings DescriberSettings) (output string, err error)
}
// DescriberSettings holds display configuration for each object
// describer to control what is printed.
type DescriberSettings struct {
ShowEvents bool
}
// ObjectDescriber is an interface for displaying arbitrary objects with extra
// information. Use when an object is in hand (on disk, or already retrieved).
// Implementers may ignore the additional information passed on extra, or use it
// by default. ObjectDescribers may return ErrNoDescriber if no suitable describer
// is found.
type ObjectDescriber interface {
DescribeObject(object interface{}, extra ...interface{}) (output string, err error)
}
// ErrNoDescriber is a structured error indicating the provided object or objects
// cannot be described.
type ErrNoDescriber struct {
Types []string
}
// Error implements the error interface.
func (e ErrNoDescriber) Error() string {
return fmt.Sprintf("no describer has been defined for %v", e.Types)
}
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"describe_test.go",
"printers_test.go",
"sorted_resource_name_list_test.go",
],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//federation/apis/federation:go_default_library",
"//federation/client/clientset_generated/federation_internalclientset/fake:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/batch:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/apis/storage:go_default_library",
"//pkg/client/clientset_generated/clientset/fake:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
"//pkg/kubectl/testing:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/util:go_default_library",
"//vendor:github.com/ghodss/yaml",
"//vendor:k8s.io/apimachinery/pkg/api/equality",
"//vendor:k8s.io/apimachinery/pkg/api/resource",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/yaml",
"//vendor:k8s.io/apimachinery/pkg/util/diff",
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
"//vendor:k8s.io/apimachinery/pkg/util/sets",
],
)
go_library(
name = "go_default_library",
srcs = [
"describe.go",
"printers.go",
],
tags = ["automanaged"],
deps = [
"//federation/apis/federation:go_default_library",
"//federation/client/clientset_generated/federation_internalclientset:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/annotations:go_default_library",
"//pkg/api/events:go_default_library",
"//pkg/apis/apps:go_default_library",
"//pkg/apis/autoscaling:go_default_library",
"//pkg/apis/batch:go_default_library",
"//pkg/apis/certificates:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/apis/policy:go_default_library",
"//pkg/apis/rbac:go_default_library",
"//pkg/apis/storage:go_default_library",
"//pkg/apis/storage/util:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library",
"//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library",
"//pkg/client/clientset_generated/clientset/typed/extensions/v1beta1:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/extensions/internalversion:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
"//pkg/fieldpath:go_default_library",
"//pkg/kubelet/qos:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/util/node:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/api/meta",
"//vendor:k8s.io/apimachinery/pkg/api/resource",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/fields",
"//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/types",
"//vendor:k8s.io/apimachinery/pkg/util/intstr",
"//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/client-go/dynamic",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package kubectl package internalversion
import ( import (
"bytes" "bytes"
...@@ -40,6 +40,7 @@ import ( ...@@ -40,6 +40,7 @@ import (
versionedfake "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake" versionedfake "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
) )
...@@ -59,7 +60,7 @@ func TestDescribePod(t *testing.T) { ...@@ -59,7 +60,7 @@ func TestDescribePod(t *testing.T) {
}) })
c := &describeClient{T: t, Namespace: "foo", Interface: fake} c := &describeClient{T: t, Namespace: "foo", Interface: fake}
d := PodDescriber{c} d := PodDescriber{c}
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true}) out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -83,7 +84,7 @@ func TestDescribePodTolerations(t *testing.T) { ...@@ -83,7 +84,7 @@ func TestDescribePodTolerations(t *testing.T) {
}) })
c := &describeClient{T: t, Namespace: "foo", Interface: fake} c := &describeClient{T: t, Namespace: "foo", Interface: fake}
d := PodDescriber{c} d := PodDescriber{c}
out, err := d.Describe("foo", "bar", DescriberSettings{}) out, err := d.Describe("foo", "bar", printers.DescriberSettings{})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -100,7 +101,7 @@ func TestDescribeNamespace(t *testing.T) { ...@@ -100,7 +101,7 @@ func TestDescribeNamespace(t *testing.T) {
}) })
c := &describeClient{T: t, Namespace: "", Interface: fake} c := &describeClient{T: t, Namespace: "", Interface: fake}
d := NamespaceDescriber{c} d := NamespaceDescriber{c}
out, err := d.Describe("", "myns", DescriberSettings{ShowEvents: true}) out, err := d.Describe("", "myns", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -118,7 +119,7 @@ func TestDescribeService(t *testing.T) { ...@@ -118,7 +119,7 @@ func TestDescribeService(t *testing.T) {
}) })
c := &describeClient{T: t, Namespace: "foo", Interface: fake} c := &describeClient{T: t, Namespace: "foo", Interface: fake}
d := ServiceDescriber{c} d := ServiceDescriber{c}
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true}) out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -167,7 +168,7 @@ func TestPodDescribeResultsSorted(t *testing.T) { ...@@ -167,7 +168,7 @@ func TestPodDescribeResultsSorted(t *testing.T) {
d := PodDescriber{c} d := PodDescriber{c}
// Act // Act
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true}) out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
// Assert // Assert
if err != nil { if err != nil {
...@@ -436,7 +437,7 @@ func TestDescribers(t *testing.T) { ...@@ -436,7 +437,7 @@ func TestDescribers(t *testing.T) {
if out, err := d.DescribeObject(first, second, third); out != "" || err == nil { if out, err := d.DescribeObject(first, second, third); out != "" || err == nil {
t.Errorf("unexpected result: %s %v", out, err) t.Errorf("unexpected result: %s %v", out, err)
} else { } else {
if noDescriber, ok := err.(ErrNoDescriber); ok { if noDescriber, ok := err.(printers.ErrNoDescriber); ok {
if !reflect.DeepEqual(noDescriber.Types, []string{"*api.Event", "*api.Pod", "*api.Pod"}) { if !reflect.DeepEqual(noDescriber.Types, []string{"*api.Event", "*api.Pod", "*api.Pod"}) {
t.Errorf("unexpected describer: %v", err) t.Errorf("unexpected describer: %v", err)
} }
...@@ -649,7 +650,7 @@ func TestPersistentVolumeDescriber(t *testing.T) { ...@@ -649,7 +650,7 @@ func TestPersistentVolumeDescriber(t *testing.T) {
for name, pv := range tests { for name, pv := range tests {
fake := fake.NewSimpleClientset(pv) fake := fake.NewSimpleClientset(pv)
c := PersistentVolumeDescriber{fake} c := PersistentVolumeDescriber{fake}
str, err := c.Describe("foo", "bar", DescriberSettings{ShowEvents: true}) str, err := c.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("Unexpected error for test %s: %v", name, err) t.Errorf("Unexpected error for test %s: %v", name, err)
} }
...@@ -673,7 +674,7 @@ func TestDescribeDeployment(t *testing.T) { ...@@ -673,7 +674,7 @@ func TestDescribeDeployment(t *testing.T) {
}, },
}) })
d := DeploymentDescriber{fake, versionedFake} d := DeploymentDescriber{fake, versionedFake}
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true}) out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -707,7 +708,7 @@ func TestDescribeCluster(t *testing.T) { ...@@ -707,7 +708,7 @@ func TestDescribeCluster(t *testing.T) {
} }
fake := fedfake.NewSimpleClientset(&cluster) fake := fedfake.NewSimpleClientset(&cluster)
d := ClusterDescriber{Interface: fake} d := ClusterDescriber{Interface: fake}
out, err := d.Describe("any", "foo", DescriberSettings{ShowEvents: true}) out, err := d.Describe("any", "foo", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -732,7 +733,7 @@ func TestDescribeStorageClass(t *testing.T) { ...@@ -732,7 +733,7 @@ func TestDescribeStorageClass(t *testing.T) {
}, },
}) })
s := StorageClassDescriber{f} s := StorageClassDescriber{f}
out, err := s.Describe("", "foo", DescriberSettings{ShowEvents: true}) out, err := s.Describe("", "foo", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -756,7 +757,7 @@ func TestDescribePodDisruptionBudget(t *testing.T) { ...@@ -756,7 +757,7 @@ func TestDescribePodDisruptionBudget(t *testing.T) {
}, },
}) })
s := PodDisruptionBudgetDescriber{f} s := PodDisruptionBudgetDescriber{f}
out, err := s.Describe("ns1", "pdb1", DescriberSettings{ShowEvents: true}) out, err := s.Describe("ns1", "pdb1", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
...@@ -1112,7 +1113,7 @@ func TestDescribeHorizontalPodAutoscaler(t *testing.T) { ...@@ -1112,7 +1113,7 @@ func TestDescribeHorizontalPodAutoscaler(t *testing.T) {
} }
fake := fake.NewSimpleClientset(&test.hpa) fake := fake.NewSimpleClientset(&test.hpa)
desc := HorizontalPodAutoscalerDescriber{fake} desc := HorizontalPodAutoscalerDescriber{fake}
str, err := desc.Describe("foo", "bar", DescriberSettings{ShowEvents: true}) str, err := desc.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("Unexpected error for test %s: %v", test.name, err) t.Errorf("Unexpected error for test %s: %v", test.name, err)
} }
...@@ -1141,7 +1142,7 @@ func TestDescribeEvents(t *testing.T) { ...@@ -1141,7 +1142,7 @@ func TestDescribeEvents(t *testing.T) {
}, },
} }
m := map[string]Describer{ m := map[string]printers.Describer{
"DaemonSetDescriber": &DaemonSetDescriber{ "DaemonSetDescriber": &DaemonSetDescriber{
fake.NewSimpleClientset(&extensions.DaemonSet{ fake.NewSimpleClientset(&extensions.DaemonSet{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
...@@ -1241,7 +1242,7 @@ func TestDescribeEvents(t *testing.T) { ...@@ -1241,7 +1242,7 @@ func TestDescribeEvents(t *testing.T) {
} }
for name, d := range m { for name, d := range m {
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true}) out, err := d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: true})
if err != nil { if err != nil {
t.Errorf("unexpected error for %q: %v", name, err) t.Errorf("unexpected error for %q: %v", name, err)
} }
...@@ -1252,7 +1253,7 @@ func TestDescribeEvents(t *testing.T) { ...@@ -1252,7 +1253,7 @@ func TestDescribeEvents(t *testing.T) {
t.Errorf("events not found for %q when ShowEvents=true: %s", name, out) t.Errorf("events not found for %q when ShowEvents=true: %s", name, out)
} }
out, err = d.Describe("foo", "bar", DescriberSettings{ShowEvents: false}) out, err = d.Describe("foo", "bar", printers.DescriberSettings{ShowEvents: false})
if err != nil { if err != nil {
t.Errorf("unexpected error for %q: %s", name, err) t.Errorf("unexpected error for %q: %s", name, err)
} }
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package kubectl package internalversion
import ( import (
"reflect" "reflect"
......
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 printers
import (
"bytes"
"encoding/json"
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
"github.com/ghodss/yaml"
)
// JSONPrinter is an implementation of ResourcePrinter which outputs an object as JSON.
type JSONPrinter struct {
}
func (p *JSONPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer.
func (p *JSONPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
switch obj := obj.(type) {
case *runtime.Unknown:
var buf bytes.Buffer
err := json.Indent(&buf, obj.Raw, "", " ")
if err != nil {
return err
}
buf.WriteRune('\n')
_, err = buf.WriteTo(w)
return err
}
data, err := json.MarshalIndent(obj, "", " ")
if err != nil {
return err
}
data = append(data, '\n')
_, err = w.Write(data)
return err
}
// TODO: implement HandledResources()
func (p *JSONPrinter) HandledResources() []string {
return []string{}
}
// YAMLPrinter is an implementation of ResourcePrinter which outputs an object as YAML.
// The input object is assumed to be in the internal version of an API and is converted
// to the given version first.
type YAMLPrinter struct {
version string
converter runtime.ObjectConvertor
}
func (p *YAMLPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj prints the data as YAML.
func (p *YAMLPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
switch obj := obj.(type) {
case *runtime.Unknown:
data, err := yaml.JSONToYAML(obj.Raw)
if err != nil {
return err
}
_, err = w.Write(data)
return err
}
output, err := yaml.Marshal(obj)
if err != nil {
return err
}
_, err = fmt.Fprint(w, string(output))
return err
}
// TODO: implement HandledResources()
func (p *YAMLPrinter) HandledResources() []string {
return []string{}
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 printers
import (
"encoding/json"
"fmt"
"io"
"reflect"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/util/jsonpath"
)
// exists returns true if it would be possible to call the index function
// with these arguments.
//
// TODO: how to document this for users?
//
// index returns the result of indexing its first argument by the following
// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
// indexed item must be a map, slice, or array.
func exists(item interface{}, indices ...interface{}) bool {
v := reflect.ValueOf(item)
for _, i := range indices {
index := reflect.ValueOf(i)
var isNil bool
if v, isNil = indirect(v); isNil {
return false
}
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
var x int64
switch index.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
x = index.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
x = int64(index.Uint())
default:
return false
}
if x < 0 || x >= int64(v.Len()) {
return false
}
v = v.Index(int(x))
case reflect.Map:
if !index.IsValid() {
index = reflect.Zero(v.Type().Key())
}
if !index.Type().AssignableTo(v.Type().Key()) {
return false
}
if x := v.MapIndex(index); x.IsValid() {
v = x
} else {
v = reflect.Zero(v.Type().Elem())
}
default:
return false
}
}
if _, isNil := indirect(v); isNil {
return false
}
return true
}
// stolen from text/template
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
// We indirect through pointers and empty interfaces (only) because
// non-empty interfaces have methods we might need.
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
if v.IsNil() {
return v, true
}
if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
break
}
}
return v, false
}
// JSONPathPrinter is an implementation of ResourcePrinter which formats data with jsonpath expression.
type JSONPathPrinter struct {
rawTemplate string
*jsonpath.JSONPath
}
func NewJSONPathPrinter(tmpl string) (*JSONPathPrinter, error) {
j := jsonpath.New("out")
if err := j.Parse(tmpl); err != nil {
return nil, err
}
return &JSONPathPrinter{tmpl, j}, nil
}
func (j *JSONPathPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj formats the obj with the JSONPath Template.
func (j *JSONPathPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
var queryObj interface{} = obj
if meta.IsListType(obj) {
data, err := json.Marshal(obj)
if err != nil {
return err
}
queryObj = map[string]interface{}{}
if err := json.Unmarshal(data, &queryObj); err != nil {
return err
}
}
if unknown, ok := obj.(*runtime.Unknown); ok {
data, err := json.Marshal(unknown)
if err != nil {
return err
}
queryObj = map[string]interface{}{}
if err := json.Unmarshal(data, &queryObj); err != nil {
return err
}
}
if unstructured, ok := obj.(runtime.Unstructured); ok {
queryObj = unstructured.UnstructuredContent()
}
if err := j.JSONPath.Execute(w, queryObj); err != nil {
fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", j.rawTemplate)
fmt.Fprintf(w, "\tobject given to jsonpath engine was:\n\t\t%#v\n\n", queryObj)
return fmt.Errorf("error executing jsonpath %q: %v\n", j.rawTemplate, err)
}
return nil
}
// TODO: implement HandledResources()
func (p *JSONPathPrinter) HandledResources() []string {
return []string{}
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 printers
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
)
// NamePrinter is an implementation of ResourcePrinter which outputs "resource/name" pair of an object.
type NamePrinter struct {
Decoders []runtime.Decoder
Typer runtime.ObjectTyper
Mapper meta.RESTMapper
}
func (p *NamePrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj is an implementation of ResourcePrinter.PrintObj which decodes the object
// and print "resource/name" pair. If the object is a List, print all items in it.
func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
if meta.IsListType(obj) {
items, err := meta.ExtractList(obj)
if err != nil {
return err
}
if errs := runtime.DecodeList(items, p.Decoders...); len(errs) > 0 {
return utilerrors.NewAggregate(errs)
}
for _, obj := range items {
if err := p.PrintObj(obj, w); err != nil {
return err
}
}
return nil
}
name := "<unknown>"
if acc, err := meta.Accessor(obj); err == nil {
if n := acc.GetName(); len(n) > 0 {
name = n
}
}
kind := obj.GetObjectKind().GroupVersionKind()
if len(kind.Kind) == 0 {
if gvks, _, err := p.Typer.ObjectKinds(obj); err == nil {
for _, gvk := range gvks {
if mappings, err := p.Mapper.RESTMappings(gvk.GroupKind(), gvk.Version); err == nil && len(mappings) > 0 {
fmt.Fprintf(w, "%s/%s\n", mappings[0].Resource, name)
}
}
} else {
fmt.Fprintf(w, "<unknown>/%s\n", name)
}
} else {
if mappings, err := p.Mapper.RESTMappings(kind.GroupKind(), kind.Version); err == nil && len(mappings) > 0 {
fmt.Fprintf(w, "%s/%s\n", mappings[0].Resource, name)
} else {
fmt.Fprintf(w, "<unknown>/%s\n", name)
}
}
return nil
}
// TODO: implement HandledResources()
func (p *NamePrinter) HandledResources() []string {
return []string{}
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 printers
import (
"fmt"
"io/ioutil"
"os"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
)
// GetStandardPrinter takes a format type, an optional format argument. It will return true
// if the format is generic (untyped), otherwise it will return false. The printer
// is agnostic to schema versions, so you must send arguments to PrintObj in the
// version you wish them to be shown using a VersionedPrinter (typically when
// generic is true).
func GetStandardPrinter(format, formatArgument string, noHeaders, allowMissingTemplateKeys bool, mapper meta.RESTMapper, typer runtime.ObjectTyper, decoders []runtime.Decoder) (ResourcePrinter, bool, error) {
var printer ResourcePrinter
switch format {
case "json":
printer = &JSONPrinter{}
case "yaml":
printer = &YAMLPrinter{}
case "name":
printer = &NamePrinter{
Typer: typer,
Decoders: decoders,
Mapper: mapper,
}
case "template", "go-template":
if len(formatArgument) == 0 {
return nil, false, fmt.Errorf("template format specified but no template given")
}
templatePrinter, err := NewTemplatePrinter([]byte(formatArgument))
if err != nil {
return nil, false, fmt.Errorf("error parsing template %s, %v\n", formatArgument, err)
}
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
printer = templatePrinter
case "templatefile", "go-template-file":
if len(formatArgument) == 0 {
return nil, false, fmt.Errorf("templatefile format specified but no template file given")
}
data, err := ioutil.ReadFile(formatArgument)
if err != nil {
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
}
templatePrinter, err := NewTemplatePrinter(data)
if err != nil {
return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
}
templatePrinter.AllowMissingKeys(allowMissingTemplateKeys)
printer = templatePrinter
case "jsonpath":
if len(formatArgument) == 0 {
return nil, false, fmt.Errorf("jsonpath template format specified but no template given")
}
jsonpathPrinter, err := NewJSONPathPrinter(formatArgument)
if err != nil {
return nil, false, fmt.Errorf("error parsing jsonpath %s, %v\n", formatArgument, err)
}
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
printer = jsonpathPrinter
case "jsonpath-file":
if len(formatArgument) == 0 {
return nil, false, fmt.Errorf("jsonpath file format specified but no template file file given")
}
data, err := ioutil.ReadFile(formatArgument)
if err != nil {
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
}
jsonpathPrinter, err := NewJSONPathPrinter(string(data))
if err != nil {
return nil, false, fmt.Errorf("error parsing template %s, %v\n", string(data), err)
}
jsonpathPrinter.AllowMissingKeys(allowMissingTemplateKeys)
printer = jsonpathPrinter
case "custom-columns":
var err error
if printer, err = NewCustomColumnsPrinterFromSpec(formatArgument, decoders[0], noHeaders); err != nil {
return nil, false, err
}
case "custom-columns-file":
file, err := os.Open(formatArgument)
if err != nil {
return nil, false, fmt.Errorf("error reading template %s, %v\n", formatArgument, err)
}
defer file.Close()
if printer, err = NewCustomColumnsPrinterFromTemplate(file, decoders[0]); err != nil {
return nil, false, err
}
case "wide":
fallthrough
case "":
return nil, false, nil
default:
return nil, false, fmt.Errorf("output format %q not recognized", format)
}
return printer, true, nil
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 printers
import (
"io"
"text/tabwriter"
)
const (
tabwriterMinWidth = 10
tabwriterWidth = 4
tabwriterPadding = 3
tabwriterPadChar = ' '
tabwriterFlags = 0
)
// GetNewTabWriter returns a tabwriter that translates tabbed columns in input into properly aligned text.
func GetNewTabWriter(output io.Writer) *tabwriter.Writer {
return tabwriter.NewWriter(output, tabwriterMinWidth, tabwriterWidth, tabwriterPadding, tabwriterPadChar, tabwriterFlags)
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 printers
import (
"encoding/json"
"fmt"
"io"
"text/template"
"k8s.io/apimachinery/pkg/runtime"
)
// TemplatePrinter is an implementation of ResourcePrinter which formats data with a Go Template.
type TemplatePrinter struct {
rawTemplate string
template *template.Template
}
func NewTemplatePrinter(tmpl []byte) (*TemplatePrinter, error) {
t, err := template.New("output").
Funcs(template.FuncMap{"exists": exists}).
Parse(string(tmpl))
if err != nil {
return nil, err
}
return &TemplatePrinter{
rawTemplate: string(tmpl),
template: t,
}, nil
}
// AllowMissingKeys tells the template engine if missing keys are allowed.
func (p *TemplatePrinter) AllowMissingKeys(allow bool) {
if allow {
p.template.Option("missingkey=default")
} else {
p.template.Option("missingkey=error")
}
}
func (p *TemplatePrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj formats the obj with the Go Template.
func (p *TemplatePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
var data []byte
var err error
data, err = json.Marshal(obj)
if err != nil {
return err
}
out := map[string]interface{}{}
if err := json.Unmarshal(data, &out); err != nil {
return err
}
if err = p.safeExecute(w, out); err != nil {
// It is way easier to debug this stuff when it shows up in
// stdout instead of just stdin. So in addition to returning
// a nice error, also print useful stuff with the writer.
fmt.Fprintf(w, "Error executing template: %v. Printing more information for debugging the template:\n", err)
fmt.Fprintf(w, "\ttemplate was:\n\t\t%v\n", p.rawTemplate)
fmt.Fprintf(w, "\traw data was:\n\t\t%v\n", string(data))
fmt.Fprintf(w, "\tobject given to template engine was:\n\t\t%+v\n\n", out)
return fmt.Errorf("error executing template %q: %v", p.rawTemplate, err)
}
return nil
}
// TODO: implement HandledResources()
func (p *TemplatePrinter) HandledResources() []string {
return []string{}
}
// safeExecute tries to execute the template, but catches panics and returns an error
// should the template engine panic.
func (p *TemplatePrinter) safeExecute(w io.Writer, obj interface{}) error {
var panicErr error
// Sorry for the double anonymous function. There's probably a clever way
// to do this that has the defer'd func setting the value to be returned, but
// that would be even less obvious.
retErr := func() error {
defer func() {
if x := recover(); x != nil {
panicErr = fmt.Errorf("caught panic: %+v", x)
}
}()
return p.template.Execute(w, obj)
}()
if panicErr != nil {
return panicErr
}
return retErr
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 printers
import (
"fmt"
"io"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// VersionedPrinter takes runtime objects and ensures they are converted to a given API version
// prior to being passed to a nested printer.
type VersionedPrinter struct {
printer ResourcePrinter
converter runtime.ObjectConvertor
versions []schema.GroupVersion
}
// NewVersionedPrinter wraps a printer to convert objects to a known API version prior to printing.
func NewVersionedPrinter(printer ResourcePrinter, converter runtime.ObjectConvertor, versions ...schema.GroupVersion) ResourcePrinter {
return &VersionedPrinter{
printer: printer,
converter: converter,
versions: versions,
}
}
func (p *VersionedPrinter) AfterPrint(w io.Writer, res string) error {
return nil
}
// PrintObj implements ResourcePrinter
func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
if len(p.versions) == 0 {
return fmt.Errorf("no version specified, object cannot be converted")
}
converted, err := p.converter.ConvertToVersion(obj, schema.GroupVersions(p.versions))
if err != nil {
return err
}
return p.printer.PrintObj(converted, w)
}
// TODO: implement HandledResources()
func (p *VersionedPrinter) HandledResources() []string {
return []string{}
}
...@@ -73,11 +73,24 @@ func (obj *Unstructured) UnstructuredContent() map[string]interface{} { ...@@ -73,11 +73,24 @@ func (obj *Unstructured) UnstructuredContent() map[string]interface{} {
} }
return obj.Object return obj.Object
} }
// UnstructuredContent returns a map contain an overlay of the Items field onto
// the Object field. Items always overwrites overlay. Changing "items" in the
// returned object will affect items in the underlying Items field, but changing
// the "items" slice itself will have no effect.
// TODO: expose SetUnstructuredContent on runtime.Unstructured that allows
// items to be changed.
func (obj *UnstructuredList) UnstructuredContent() map[string]interface{} { func (obj *UnstructuredList) UnstructuredContent() map[string]interface{} {
if obj.Object == nil { out := obj.Object
obj.Object = make(map[string]interface{}) if out == nil {
out = make(map[string]interface{})
} }
return obj.Object items := make([]interface{}, len(obj.Items))
for i, item := range obj.Items {
items[i] = item.Object
}
out["items"] = items
return out
} }
// MarshalJSON ensures that the unstructured object produces proper // MarshalJSON ensures that the unstructured object produces proper
......
/*
Copyright 2017 The Kubernetes Authors.
Licensed 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 unstructured
import "testing"
func TestUnstructuredList(t *testing.T) {
list := &UnstructuredList{
Object: map[string]interface{}{"kind": "List", "apiVersion": "v1"},
Items: []*Unstructured{
{Object: map[string]interface{}{"kind": "Pod", "apiVersion": "v1", "metadata": map[string]interface{}{"name": "test"}}},
},
}
content := list.UnstructuredContent()
items := content["items"].([]interface{})
if len(items) != 1 {
t.Fatalf("unexpected items: %#v", items)
}
if getNestedField(items[0].(map[string]interface{}), "metadata", "name") != "test" {
t.Fatalf("unexpected fields: %#v", items[0])
}
}
...@@ -17116,3 +17116,10 @@ go_library( ...@@ -17116,3 +17116,10 @@ go_library(
"//vendor:k8s.io/kube-aggregator/pkg/apis/apiregistration/install", "//vendor:k8s.io/kube-aggregator/pkg/apis/apiregistration/install",
], ],
) )
go_test(
name = "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured_test",
srcs = ["k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructured_test.go"],
library = ":k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
tags = ["automanaged"],
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment