github.com/SamarSidharth/kpt@v0.0.0-20231122062228-c7d747ae3ace/commands/pkg/update/cmdupdate.go (about) 1 // Copyright 2019 The kpt Authors 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 update 16 17 import ( 18 "context" 19 "fmt" 20 "os" 21 "path/filepath" 22 "strings" 23 24 docs "github.com/GoogleContainerTools/kpt/internal/docs/generated/pkgdocs" 25 "github.com/GoogleContainerTools/kpt/internal/errors" 26 "github.com/GoogleContainerTools/kpt/internal/pkg" 27 "github.com/GoogleContainerTools/kpt/internal/types" 28 "github.com/GoogleContainerTools/kpt/internal/util/argutil" 29 "github.com/GoogleContainerTools/kpt/internal/util/cmdutil" 30 "github.com/GoogleContainerTools/kpt/internal/util/pathutil" 31 "github.com/GoogleContainerTools/kpt/internal/util/update" 32 kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" 33 "github.com/spf13/cobra" 34 "sigs.k8s.io/kustomize/kyaml/filesys" 35 ) 36 37 // NewRunner returns a command runner. 38 func NewRunner(ctx context.Context, parent string) *Runner { 39 r := &Runner{ 40 ctx: ctx, 41 } 42 c := &cobra.Command{ 43 Use: "update [PKG_PATH@VERSION] [flags]", 44 Short: docs.UpdateShort, 45 Long: docs.UpdateShort + "\n" + docs.UpdateLong, 46 Example: docs.UpdateExamples, 47 RunE: r.runE, 48 Args: cobra.MaximumNArgs(1), 49 PreRunE: r.preRunE, 50 SuggestFor: []string{"rebase", "replace"}, 51 } 52 53 c.Flags().StringVar(&r.strategy, "strategy", string(kptfilev1.ResourceMerge), 54 "the update strategy that will be used when updating the package. This will change "+ 55 "the default strategy for the package -- must be one of: "+ 56 strings.Join(kptfilev1.UpdateStrategiesAsStrings(), ",")) 57 _ = c.RegisterFlagCompletionFunc("strategy", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 58 return kptfilev1.UpdateStrategiesAsStrings(), cobra.ShellCompDirectiveDefault 59 }) 60 cmdutil.FixDocs("kpt", parent, c) 61 r.Command = c 62 return r 63 } 64 65 func NewCommand(ctx context.Context, parent string) *cobra.Command { 66 return NewRunner(ctx, parent).Command 67 } 68 69 // Runner contains the run function. 70 // TODO, support listing versions 71 type Runner struct { 72 ctx context.Context 73 strategy string 74 Update update.Command 75 Command *cobra.Command 76 } 77 78 func (r *Runner) preRunE(_ *cobra.Command, args []string) error { 79 const op errors.Op = "cmdupdate.preRunE" 80 if len(args) == 0 { 81 args = append(args, pkg.CurDir) 82 } 83 if r.strategy == "" { 84 r.Update.Strategy = kptfilev1.ResourceMerge 85 } else { 86 r.Update.Strategy = kptfilev1.UpdateStrategyType(r.strategy) 87 } 88 89 parts := strings.Split(args[0], "@") 90 if len(parts) > 2 { 91 return errors.E(op, errors.InvalidParam, fmt.Errorf("at most 1 version permitted")) 92 } 93 94 resolvedPath, err := argutil.ResolveSymlink(r.ctx, parts[0]) 95 if err != nil { 96 return err 97 } 98 absResolvedPath, _, err := pathutil.ResolveAbsAndRelPaths(resolvedPath) 99 if err != nil { 100 return err 101 } 102 p, err := pkg.New(filesys.FileSystemOrOnDisk{}, absResolvedPath) 103 if err != nil { 104 return errors.E(op, err) 105 } 106 107 r.Update.Pkg = p 108 109 // TODO: Make sure we handle this in a centralized library and do 110 // this consistently across all commands. 111 relPath, err := resolveRelPath(p.UniquePath) 112 if err != nil { 113 return errors.E(op, p.UniquePath, err) 114 } 115 if strings.HasPrefix(relPath, pkg.ParentDir) { 116 return errors.E(op, p.UniquePath, fmt.Errorf("package path must be under current working directory")) 117 } 118 119 if len(parts) > 1 { 120 r.Update.Ref = parts[1] 121 } 122 return nil 123 } 124 125 func (r *Runner) runE(_ *cobra.Command, _ []string) error { 126 const op errors.Op = "cmdupdate.runE" 127 if err := r.Update.Run(r.ctx); err != nil { 128 return errors.E(op, r.Update.Pkg.UniquePath, err) 129 } 130 131 return nil 132 } 133 134 func resolveRelPath(path types.UniquePath) (string, error) { 135 const op errors.Op = "cmdupdate.resolveRelPath" 136 cwd, err := os.Getwd() 137 if err != nil { 138 return "", errors.E(op, errors.IO, 139 fmt.Errorf("error looking up current working directory: %w", err)) 140 } 141 142 relPath, err := filepath.Rel(cwd, path.String()) 143 if err != nil { 144 return "", errors.E(op, errors.IO, 145 fmt.Errorf("error resolving the relative path: %w", err)) 146 } 147 return relPath, nil 148 }