github.com/KusionStack/kpm@v0.8.4-0.20240326033734-dc72298a30e5/pkg/cmd/cmd_push.go (about) 1 // Copyright 2023 The KCL Authors. All rights reserved. 2 // Deprecated: The entire contents of this file will be deprecated. 3 // Please use the kcl cli - https://github.com/kcl-lang/cli. 4 5 package cmd 6 7 import ( 8 "fmt" 9 "net/url" 10 "os" 11 12 "github.com/urfave/cli/v2" 13 "kcl-lang.io/kpm/pkg/client" 14 "kcl-lang.io/kpm/pkg/errors" 15 "kcl-lang.io/kpm/pkg/oci" 16 "kcl-lang.io/kpm/pkg/opt" 17 pkg "kcl-lang.io/kpm/pkg/package" 18 "kcl-lang.io/kpm/pkg/reporter" 19 "kcl-lang.io/kpm/pkg/utils" 20 ) 21 22 // NewPushCmd new a Command for `kpm push`. 23 func NewPushCmd(kpmcli *client.KpmClient) *cli.Command { 24 return &cli.Command{ 25 Hidden: false, 26 Name: "push", 27 Usage: "push kcl package to OCI registry.", 28 Flags: []cli.Flag{ 29 &cli.StringFlag{ 30 Name: FLAG_TAR_PATH, 31 Usage: "a kcl file as the compile entry file", 32 }, 33 // '--vendor' will trigger the vendor mode 34 // In the vendor mode, the package search path is the subdirectory 'vendor' in current package. 35 // In the non-vendor mode, the package search path is the $KCL_PKG_PATH. 36 &cli.BoolFlag{ 37 Name: FLAG_VENDOR, 38 Usage: "push in vendor mode", 39 }, 40 }, 41 Action: func(c *cli.Context) error { 42 return KpmPush(c, kpmcli) 43 }, 44 } 45 } 46 47 func KpmPush(c *cli.Context, kpmcli *client.KpmClient) error { 48 localTarPath := c.String(FLAG_TAR_PATH) 49 ociUrl := c.Args().First() 50 51 var err error 52 53 if len(localTarPath) == 0 { 54 // If the tar package to be pushed is not specified, 55 // the current kcl package is packaged into tar and pushed. 56 err = pushCurrentPackage(ociUrl, c.Bool(FLAG_VENDOR), kpmcli) 57 } else { 58 // Else push the tar package specified. 59 err = pushTarPackage(ociUrl, localTarPath, c.Bool(FLAG_VENDOR), kpmcli) 60 } 61 62 if err != nil { 63 return err 64 } 65 66 return nil 67 } 68 69 // genDefaultOciUrlForKclPkg will generate the default oci url from the current package. 70 func genDefaultOciUrlForKclPkg(pkg *pkg.KclPkg, kpmcli *client.KpmClient) (string, error) { 71 72 urlPath := utils.JoinPath(kpmcli.GetSettings().DefaultOciRepo(), pkg.GetPkgName()) 73 74 u := &url.URL{ 75 Scheme: oci.OCI_SCHEME, 76 Host: kpmcli.GetSettings().DefaultOciRegistry(), 77 Path: urlPath, 78 } 79 80 return u.String(), nil 81 } 82 83 // pushCurrentPackage will push the current package to the oci registry. 84 func pushCurrentPackage(ociUrl string, vendorMode bool, kpmcli *client.KpmClient) error { 85 pwd, err := os.Getwd() 86 87 if err != nil { 88 reporter.ReportEventToStderr(reporter.NewEvent(reporter.Bug, "internal bug: failed to load working directory")) 89 return err 90 } 91 // 1. Load the current kcl packege. 92 kclPkg, err := pkg.LoadKclPkg(pwd) 93 94 if err != nil { 95 reporter.ReportEventToStderr(reporter.NewEvent(reporter.FailedLoadKclMod, fmt.Sprintf("failed to load package in '%s'", pwd))) 96 return err 97 } 98 99 // 2. push the package 100 return pushPackage(ociUrl, kclPkg, vendorMode, kpmcli) 101 } 102 103 // pushTarPackage will push the kcl package in tarPath to the oci registry. 104 // If the tar in 'tarPath' is not a kcl package tar, pushTarPackage will return an error. 105 func pushTarPackage(ociUrl, localTarPath string, vendorMode bool, kpmcli *client.KpmClient) error { 106 var kclPkg *pkg.KclPkg 107 var err error 108 109 // clean the temp dir used to untar kcl package tar file. 110 defer func() { 111 if kclPkg != nil && utils.DirExists(kclPkg.HomePath) { 112 err = os.RemoveAll(kclPkg.HomePath) 113 if err != nil { 114 err = reporter.NewErrorEvent(reporter.Bug, err, "internal bugs, failed to clean the temp dir.") 115 } 116 } 117 }() 118 119 // 1. load the kcl package from the tar path. 120 kclPkg, err = pkg.LoadKclPkgFromTar(localTarPath) 121 if err != nil { 122 return err 123 } 124 125 // 2. push the package 126 return pushPackage(ociUrl, kclPkg, vendorMode, kpmcli) 127 } 128 129 // pushPackage will push the kcl package to the oci registry. 130 // 1. pushPackage will package the current kcl package into default tar path. 131 // 2. If the oci url is not specified, generate the default oci url from the current package. 132 // 3. Generate the OCI options from oci url and the version of current kcl package. 133 // 4. Push the package to the oci registry. 134 func pushPackage(ociUrl string, kclPkg *pkg.KclPkg, vendorMode bool, kpmcli *client.KpmClient) error { 135 136 tarPath, err := kpmcli.PackagePkg(kclPkg, vendorMode) 137 if err != nil { 138 return err 139 } 140 141 // clean the tar path. 142 defer func() { 143 if kclPkg != nil && utils.DirExists(tarPath) { 144 err = os.RemoveAll(tarPath) 145 if err != nil { 146 err = reporter.NewErrorEvent(reporter.Bug, err, "internal bugs, failed to clean the temp dir.") 147 } 148 } 149 }() 150 151 // 2. If the oci url is not specified, generate the default oci url from the current package. 152 if len(ociUrl) == 0 { 153 ociUrl, err = genDefaultOciUrlForKclPkg(kclPkg, kpmcli) 154 if err != nil || len(ociUrl) == 0 { 155 return reporter.NewErrorEvent( 156 reporter.InvalidCmd, 157 fmt.Errorf("failed to generate default oci url for current package"), 158 "run 'kpm push help' for more information", 159 ) 160 } 161 } 162 163 // 3. Generate the OCI options from oci url and the version of current kcl package. 164 ociOpts, err := opt.ParseOciOptionFromOciUrl(ociUrl, kclPkg.GetPkgTag()) 165 if err != (*reporter.KpmEvent)(nil) { 166 return reporter.NewErrorEvent( 167 reporter.UnsupportOciUrlScheme, 168 errors.InvalidOciUrl, 169 "only support url scheme 'oci://'", 170 ) 171 } 172 173 ociOpts.Annotations, err = oci.GenOciManifestFromPkg(kclPkg) 174 if err != nil { 175 return err 176 } 177 178 reporter.ReportMsgTo(fmt.Sprintf("package '%s' will be pushed", kclPkg.GetPkgName()), kpmcli.GetLogWriter()) 179 // 4. Push it. 180 err = kpmcli.PushToOci(tarPath, ociOpts) 181 if err != (*reporter.KpmEvent)(nil) { 182 return err 183 } 184 return nil 185 }