github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/commands/alpha/repo/get/command.go (about)

     1  // Copyright 2022 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package get
    16  
    17  import (
    18  	"context"
    19  	"strings"
    20  
    21  	"github.com/GoogleContainerTools/kpt/internal/docs/generated/repodocs"
    22  	"github.com/GoogleContainerTools/kpt/internal/errors"
    23  	"github.com/GoogleContainerTools/kpt/internal/options"
    24  	"github.com/GoogleContainerTools/kpt/internal/util/porch"
    25  	"github.com/spf13/cobra"
    26  	"k8s.io/cli-runtime/pkg/genericclioptions"
    27  	"k8s.io/cli-runtime/pkg/printers"
    28  	"k8s.io/client-go/rest"
    29  	"k8s.io/kubectl/pkg/cmd/get"
    30  )
    31  
    32  const (
    33  	command = "cmdrepoget"
    34  )
    35  
    36  func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command {
    37  	return newRunner(ctx, rcg).Command
    38  }
    39  
    40  func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner {
    41  	r := &runner{
    42  		ctx:        ctx,
    43  		getFlags:   options.Get{ConfigFlags: rcg},
    44  		printFlags: get.NewGetPrintFlags(),
    45  	}
    46  	c := &cobra.Command{
    47  		Use:     "get [REPOSITORY_NAME]",
    48  		Aliases: []string{"ls", "list"},
    49  		Short:   repodocs.GetShort,
    50  		Long:    repodocs.GetShort + "\n" + repodocs.GetLong,
    51  		Example: repodocs.GetExamples,
    52  		PreRunE: r.preRunE,
    53  		RunE:    r.runE,
    54  		Hidden:  porch.HidePorchCommands,
    55  	}
    56  	r.Command = c
    57  
    58  	// Create flags
    59  	r.getFlags.AddFlags(c)
    60  	r.printFlags.AddFlags(c)
    61  	return r
    62  }
    63  
    64  type runner struct {
    65  	ctx     context.Context
    66  	Command *cobra.Command
    67  
    68  	// Flags
    69  	getFlags   options.Get
    70  	printFlags *get.PrintFlags
    71  
    72  	requestTable bool
    73  }
    74  
    75  func (r *runner) preRunE(cmd *cobra.Command, args []string) error {
    76  	outputOption := cmd.Flags().Lookup("output").Value.String()
    77  	if strings.Contains(outputOption, "custom-columns") || outputOption == "yaml" || strings.Contains(outputOption, "json") {
    78  		r.requestTable = false
    79  	} else {
    80  		r.requestTable = true
    81  	}
    82  	return nil
    83  }
    84  
    85  func (r *runner) runE(cmd *cobra.Command, args []string) error {
    86  	const op errors.Op = command + ".runE"
    87  
    88  	// For some reason our use of k8s libraries result in error when decoding
    89  	// RepositoryList when we use strongly typed data. Therefore for now we
    90  	// use unstructured communication.
    91  	// The error is: `no kind "RepositoryList" is registered for the internal
    92  	// version of group "config.porch.kpt.dev" in scheme`. Of course there _is_
    93  	// no such kind since CRDs seem to have only versioned resources.
    94  	b, err := r.getFlags.ResourceBuilder()
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	// TODO: Support table mode over proto
   100  	// TODO: Print namespace in multi-namespace mode
   101  	b = b.Unstructured()
   102  
   103  	if len(args) > 0 {
   104  		b.ResourceNames("repository", args...)
   105  	} else {
   106  		b = b.SelectAllParam(true).
   107  			ResourceTypes("repository")
   108  	}
   109  
   110  	b = b.ContinueOnError().Latest().Flatten()
   111  
   112  	if r.requestTable {
   113  		b = b.TransformRequests(func(req *rest.Request) {
   114  			req.SetHeader("Accept", strings.Join([]string{
   115  				"application/json;as=Table;g=meta.k8s.io;v=v1",
   116  				"application/json",
   117  			}, ","))
   118  		})
   119  	}
   120  	res := b.Do()
   121  	if err := res.Err(); err != nil {
   122  		return errors.E(op, err)
   123  	}
   124  
   125  	infos, err := res.Infos()
   126  	if err != nil {
   127  		return errors.E(op, err)
   128  	}
   129  
   130  	printer, err := r.printFlags.ToPrinter()
   131  	if err != nil {
   132  		return errors.E(op, err)
   133  	}
   134  
   135  	if r.requestTable {
   136  		printer = &get.TablePrinter{
   137  			Delegate: printer,
   138  		}
   139  	}
   140  
   141  	w := printers.GetNewTabWriter(cmd.OutOrStdout())
   142  
   143  	for _, i := range infos {
   144  		if err := printer.PrintObj(i.Object, w); err != nil {
   145  			return errors.E(op, err)
   146  		}
   147  	}
   148  
   149  	if err := w.Flush(); err != nil {
   150  		return errors.E(op, err)
   151  	}
   152  
   153  	return nil
   154  }