Skip to content

Commit d9311b7

Browse files
committed
feat: add 'cat' command for displaying package resources
Signed-off-by: Aravindhan Ayyanathan <aravindhan.a@est.tech>
1 parent fbe7b3e commit d9311b7

3 files changed

Lines changed: 673 additions & 2 deletions

File tree

commands/pkg/pkgcmd.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019 The kpt Authors
1+
// Copyright 2019-2026 The kpt Authors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import (
2222
initialization "github.com/kptdev/kpt/commands/pkg/init"
2323
"github.com/kptdev/kpt/commands/pkg/update"
2424
"github.com/kptdev/kpt/internal/docs/generated/pkgdocs"
25+
"github.com/kptdev/kpt/thirdparty/cmdconfig/commands/cmdcat"
2526
"github.com/kptdev/kpt/thirdparty/cmdconfig/commands/cmdtree"
2627
"github.com/spf13/cobra"
2728
)
@@ -47,7 +48,7 @@ func GetCommand(ctx context.Context, name string) *cobra.Command {
4748
pkg.AddCommand(
4849
get.NewCommand(ctx, name), initialization.NewCommand(ctx, name),
4950
update.NewCommand(ctx, name), diff.NewCommand(ctx, name),
50-
cmdtree.NewCommand(ctx, name),
51+
cmdtree.NewCommand(ctx, name), cmdcat.NewCommand(ctx, name),
5152
)
5253
return pkg
5354
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
// Copyright 2019-2026 The Kpt Authors.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package cmdcat
5+
6+
import (
7+
"bytes"
8+
"context"
9+
"fmt"
10+
"io"
11+
"os"
12+
"path/filepath"
13+
"strings"
14+
15+
"github.com/kptdev/kpt/internal/docs/generated/pkgdocs"
16+
kptfilev1 "github.com/kptdev/kpt/pkg/api/kptfile/v1"
17+
"github.com/kptdev/kpt/thirdparty/cmdconfig/commands/runner"
18+
"github.com/spf13/cobra"
19+
"sigs.k8s.io/kustomize/kyaml/kio"
20+
"sigs.k8s.io/kustomize/kyaml/kio/filters"
21+
"sigs.k8s.io/kustomize/kyaml/yaml"
22+
)
23+
24+
// GetCatRunner returns a command CatRunner.
25+
func GetCatRunner(ctx context.Context, _ string) *CatRunner {
26+
r := &CatRunner{
27+
Ctx: ctx,
28+
errWriter: os.Stderr,
29+
}
30+
c := &cobra.Command{
31+
Use: "cat [FILE | DIR]",
32+
Short: pkgdocs.CatShort,
33+
Long: pkgdocs.CatLong,
34+
Example: pkgdocs.CatExamples,
35+
RunE: r.runE,
36+
Args: cobra.MaximumNArgs(1),
37+
}
38+
c.Flags().BoolVar(&r.Format, "format", true,
39+
"format resource config yaml before printing.")
40+
c.Flags().BoolVar(&r.KeepAnnotations, "annotate", false,
41+
"annotate resources with their file origins.")
42+
c.Flags().StringSliceVar(&r.Styles, "style", []string{},
43+
"yaml styles to apply. may be 'TaggedStyle', 'DoubleQuotedStyle', 'LiteralStyle', "+
44+
"'FoldedStyle', 'FlowStyle'.")
45+
c.Flags().BoolVar(&r.StripComments, "strip-comments", false,
46+
"remove comments from yaml.")
47+
c.Flags().BoolVarP(&r.RecurseSubPackages, "recurse-subpackages", "R", true,
48+
"print resources recursively in all the nested subpackages")
49+
r.Command = c
50+
return r
51+
}
52+
53+
func NewCommand(ctx context.Context, name string) *cobra.Command {
54+
return GetCatRunner(ctx, name).Command
55+
}
56+
57+
// CatRunner contains the run function
58+
type CatRunner struct {
59+
Command *cobra.Command
60+
Ctx context.Context
61+
Format bool
62+
KeepAnnotations bool
63+
Styles []string
64+
StripComments bool
65+
RecurseSubPackages bool
66+
errWriter io.Writer
67+
}
68+
69+
func (r *CatRunner) runE(c *cobra.Command, args []string) error {
70+
var writer = c.OutOrStdout()
71+
if len(args) == 0 {
72+
args = append(args, ".")
73+
}
74+
75+
if info, err := os.Stat(args[0]); err == nil && !info.IsDir() {
76+
switch strings.ToLower(filepath.Ext(args[0])) {
77+
case ".yaml", ".yml", ".json":
78+
default:
79+
return fmt.Errorf("%q is not a YAML/JSON file; no resources will be read", args[0])
80+
}
81+
}
82+
83+
out := &bytes.Buffer{}
84+
e := runner.ExecuteCmdOnPkgs{
85+
Writer: out,
86+
NeedOpenAPI: false,
87+
RecurseSubPackages: r.RecurseSubPackages,
88+
CmdRunner: r,
89+
RootPkgPath: filepath.Clean(args[0]),
90+
SkipPkgPathPrint: true,
91+
}
92+
93+
err := e.Execute()
94+
if err != nil {
95+
return err
96+
}
97+
98+
res := strings.TrimSuffix(out.String(), "---\n")
99+
res = strings.TrimSuffix(res, "---")
100+
fmt.Fprintf(writer, "%s", res)
101+
102+
return nil
103+
}
104+
105+
func (r *CatRunner) ExecuteCmd(w io.Writer, pkgPath string) error {
106+
input := kio.LocalPackageReader{PackagePath: pkgPath, PackageFileName: kptfilev1.KptFileName}
107+
out := &bytes.Buffer{}
108+
err := kio.Pipeline{
109+
Inputs: []kio.Reader{input},
110+
Filters: r.catFilters(),
111+
Outputs: r.out(out),
112+
}.Execute()
113+
114+
if err != nil {
115+
// Emit a contextual diagnostic on stderr so the user knows which
116+
// package failed; the runner currently aborts on the first error.
117+
fmt.Fprintf(r.errWriter, "kpt pkg cat: %s in package %q\n", err.Error(), pkgPath)
118+
return err
119+
}
120+
fmt.Fprint(w, out.String())
121+
if out.String() != "" {
122+
fmt.Fprint(w, "---")
123+
}
124+
return nil
125+
}
126+
127+
func (r *CatRunner) catFilters() []kio.Filter {
128+
var fltrs []kio.Filter
129+
if r.Format {
130+
fltrs = append(fltrs, filters.FormatFilter{})
131+
}
132+
if r.StripComments {
133+
fltrs = append(fltrs, filters.StripCommentsFilter{})
134+
}
135+
return fltrs
136+
}
137+
138+
func (r *CatRunner) out(w io.Writer) []kio.Writer {
139+
var outputs []kio.Writer
140+
var functionConfig *yaml.RNode
141+
142+
// remove these annotations explicitly; the ByteWriter won't clear them by
143+
// default because they were set by the LocalPackageReader, not by it.
144+
clear := []string{
145+
"config.kubernetes.io/path",
146+
"internal.config.kubernetes.io/path",
147+
}
148+
if r.KeepAnnotations {
149+
clear = nil
150+
}
151+
152+
outputs = append(outputs, kio.ByteWriter{
153+
Writer: w,
154+
KeepReaderAnnotations: r.KeepAnnotations,
155+
FunctionConfig: functionConfig,
156+
Style: yaml.GetStyle(r.Styles...),
157+
ClearAnnotations: clear,
158+
})
159+
160+
return outputs
161+
}

0 commit comments

Comments
 (0)