Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add '--vendor' to control whether all the dependencies are packaged together. #152

Merged
merged 2 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion pkg/cmd/cmd_pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ func NewPkgCmd() *cli.Command {
Name: "target",
Usage: "Packaged target path",
},
// '--vendor' will trigger the vendor mode
// In the vendor mode, the package search path is the subdirectory 'vendor' in current package.
// In the non-vendor mode, the package search path is the $KCL_PKG_PATH.
&cli.BoolFlag{
Name: FLAG_VENDOR,
Usage: "push in vendor mode",
},
},
Action: func(c *cli.Context) error {
tarPath := c.String("target")
Expand Down Expand Up @@ -54,7 +61,7 @@ func NewPkgCmd() *cli.Command {
}
}
// The method for packaging kcl package should be a member method of KclPkg.
return kclPkg.PackageToTarball(filepath.Join(tarPath, kclPkg.GetPkgTarName()))
return kclPkg.PackageToTarball(filepath.Join(tarPath, kclPkg.GetPkgTarName()), c.Bool(FLAG_VENDOR))
},
}
}
23 changes: 15 additions & 8 deletions pkg/cmd/cmd_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ func NewPushCmd(settings *settings.Settings) *cli.Command {
Name: FLAG_TAR_PATH,
Usage: "a kcl file as the compile entry file",
},
// '--vendor' will trigger the vendor mode
// In the vendor mode, the package search path is the subdirectory 'vendor' in current package.
// In the non-vendor mode, the package search path is the $KCL_PKG_PATH.
&cli.BoolFlag{
Name: FLAG_VENDOR,
Usage: "push in vendor mode",
},
},
Action: func(c *cli.Context) error {

Expand All @@ -38,10 +45,10 @@ func NewPushCmd(settings *settings.Settings) *cli.Command {
if len(localTarPath) == 0 {
// If the tar package to be pushed is not specified,
// the current kcl package is packaged into tar and pushed.
err = pushCurrentPackage(ociUrl, settings)
err = pushCurrentPackage(ociUrl, c.Bool(FLAG_VENDOR), settings)
} else {
// Else push the tar package specified.
err = pushTarPackage(ociUrl, localTarPath, settings)
err = pushTarPackage(ociUrl, localTarPath, c.Bool(FLAG_VENDOR), settings)
}

if err != nil {
Expand Down Expand Up @@ -72,7 +79,7 @@ func genDefaultOciUrlForKclPkg(pkg *pkg.KclPkg) (string, error) {
}

// pushCurrentPackage will push the current package to the oci registry.
func pushCurrentPackage(ociUrl string, settings *settings.Settings) error {
func pushCurrentPackage(ociUrl string, vendorMode bool, settings *settings.Settings) error {
pwd, err := os.Getwd()

if err != nil {
Expand All @@ -87,12 +94,12 @@ func pushCurrentPackage(ociUrl string, settings *settings.Settings) error {
}

// 2. push the package
return pushPackage(ociUrl, kclPkg, settings)
return pushPackage(ociUrl, kclPkg, vendorMode, settings)
}

// pushTarPackage will push the kcl package in tarPath to the oci registry.
// If the tar in 'tarPath' is not a kcl package tar, pushTarPackage will return an error.
func pushTarPackage(ociUrl, localTarPath string, settings *settings.Settings) error {
func pushTarPackage(ociUrl, localTarPath string, vendorMode bool, settings *settings.Settings) error {
var kclPkg *pkg.KclPkg
var err error

Expand All @@ -113,17 +120,17 @@ func pushTarPackage(ociUrl, localTarPath string, settings *settings.Settings) er
}

// 2. push the package
return pushPackage(ociUrl, kclPkg, settings)
return pushPackage(ociUrl, kclPkg, vendorMode, settings)
}

// pushPackage will push the kcl package to the oci registry.
// 1. pushPackage will package the current kcl package into default tar path.
// 2. If the oci url is not specified, generate the default oci url from the current package.
// 3. Generate the OCI options from oci url and the version of current kcl package.
// 4. Push the package to the oci registry.
func pushPackage(ociUrl string, kclPkg *pkg.KclPkg, settings *settings.Settings) error {
func pushPackage(ociUrl string, kclPkg *pkg.KclPkg, vendorMode bool, settings *settings.Settings) error {
// 1. Package the current kcl package into default tar path.
tarPath, err := kclPkg.PackageCurrentPkgPath()
tarPath, err := kclPkg.PackageCurrentPkgPath(vendorMode)
if err != nil {
return err
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/package/modfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ type Dependency struct {
Source `json:"-"`
}

// GetLocalFullPath will get the local path of a dependency.
func (dep *Dependency) GetLocalFullPath() string {
if dep.isFromLocal() {
return dep.Source.Local.Path
}
return dep.LocalFullPath
}

func (dep *Dependency) isFromLocal() bool {
return dep.Source.Oci == nil && dep.Source.Git == nil && dep.Source.Local != nil
}
Expand Down
26 changes: 17 additions & 9 deletions pkg/package/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ func check(dep Dependency, newDepPath string) bool {
// And the tar will be named "<package_name>-<package_version>.tar"
// <package_name> is the package name specified in kcl.mod.
// <package_version> is the package version specified in kcl.mod.
func (kclPkg *KclPkg) PackageCurrentPkgPath() (string, error) {
func (kclPkg *KclPkg) PackageCurrentPkgPath(vendorMode bool) (string, error) {
globalPkgPath, err := env.GetAbsPkgPath()
if err != nil {
return "", err
Expand All @@ -448,7 +448,7 @@ func (kclPkg *KclPkg) PackageCurrentPkgPath() (string, error) {
return "", err
}

err = kclPkg.PackageKclPkg(globalPkgPath, kclPkg.DefaultTarPath())
err = kclPkg.PackageKclPkg(globalPkgPath, kclPkg.DefaultTarPath(), vendorMode)

if err != nil {
reporter.ExitWithReport("kpm: failed to package pkg " + kclPkg.GetPkgName() + ".")
Expand All @@ -465,7 +465,7 @@ func (kclPkg *KclPkg) DefaultTarPath() string {
}

// PkgCurrentPackageIntoTarPath will package the current kcl package into 'tarPath'.
func (kclPkg *KclPkg) PackageToTarball(tarPath string) error {
func (kclPkg *KclPkg) PackageToTarball(tarPath string, vendorMode bool) error {

globalPkgPath, err := env.GetAbsPkgPath()
if err != nil {
Expand All @@ -477,7 +477,7 @@ func (kclPkg *KclPkg) PackageToTarball(tarPath string) error {
return err
}

err = kclPkg.PackageKclPkg(globalPkgPath, tarPath)
err = kclPkg.PackageKclPkg(globalPkgPath, tarPath, vendorMode)

if err != nil {
reporter.ExitWithReport("kpm: failed to package pkg " + kclPkg.GetPkgName() + ".")
Expand All @@ -488,15 +488,17 @@ func (kclPkg *KclPkg) PackageToTarball(tarPath string) error {

// PackageKclPkg will save all dependencies to the 'vendor' in current pacakge
// and package the current package into tar
func (kclPkg *KclPkg) PackageKclPkg(kpmHome string, tarPath string) error {
func (kclPkg *KclPkg) PackageKclPkg(kpmHome string, tarPath string, vendorMode bool) error {
// Vendor all the dependencies into the current kcl package.
err := kclPkg.VendorDeps(kpmHome)
if err != nil {
return errors.FailedToVendorDependency
if vendorMode {
err := kclPkg.VendorDeps(kpmHome)
if err != nil {
return errors.FailedToVendorDependency
}
}

// Tar the current kcl package into a "*.tar" file.
err = utils.TarDir(kclPkg.HomePath, tarPath)
err := utils.TarDir(kclPkg.HomePath, tarPath)
if err != nil {
return errors.FailedToPackage
}
Expand Down Expand Up @@ -537,6 +539,12 @@ func (kclPkg *KclPkg) VendorDeps(cachePath string) error {
if err != nil {
return errors.FailedToVendorDependency
}
} else if utils.DirExists(d.GetLocalFullPath()) && check(d, d.GetLocalFullPath()) {
// If there is, copy it into the 'vendor' directory.
err := copy.Copy(d.GetLocalFullPath(), vendorFullPath)
if err != nil {
return errors.FailedToVendorDependency
}
} else {
// re-download if not.
err = kclPkg.DownloadDep(&d, cachePath)
Expand Down
82 changes: 81 additions & 1 deletion pkg/package/package_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package pkg

import (
"archive/tar"
"encoding/json"
"fmt"
"io"
"log"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -417,7 +420,7 @@ func TestPackageCurrentPkgPath(t *testing.T) {

assert.Equal(t, utils.DirExists(filepath.Join(testDir, kclPkg.GetPkgTarName())), false)

path, err := kclPkg.PackageCurrentPkgPath()
path, err := kclPkg.PackageCurrentPkgPath(true)
assert.Equal(t, err, nil)
assert.Equal(t, path, filepath.Join(testDir, kclPkg.GetPkgTarName()))
assert.Equal(t, utils.DirExists(filepath.Join(testDir, kclPkg.GetPkgTarName())), true)
Expand Down Expand Up @@ -548,3 +551,80 @@ func TestResolveMetadataInJsonStr(t *testing.T) {
expectedStr := "{\"packages\":{\"konfig\":{\"name\":\"konfig\",\"manifest_path\":\"\"}}}"
assert.Equal(t, res, expectedStr)
}

func TestPkgWithInVendorMode(t *testing.T) {
testDir := getTestDir("test_pkg_with_vendor")
kcl1Path := filepath.Join(testDir, "kcl1")

createKclPkg1 := func() {
assert.Equal(t, utils.DirExists(kcl1Path), false)
err := os.MkdirAll(kcl1Path, 0755)
assert.Equal(t, err, nil)
}

defer func() {
if err := os.RemoveAll(kcl1Path); err != nil {
log.Printf("failed to close file: %v", err)
}
}()

createKclPkg1()

initOpts := opt.InitOptions{
Name: "kcl1",
InitPath: kcl1Path,
}
kclPkg1 := NewKclPkg(&initOpts)

err := kclPkg1.AddDeps(&opt.AddOptions{
LocalPath: "localPath",
RegistryOpts: opt.RegistryOptions{
Local: &opt.LocalOptions{
Path: filepath.Join(testDir, "kcl2"),
},
},
})

assert.Equal(t, err, nil)

// package the kcl1 into tar in vendor mode.
tarPath, err := kclPkg1.PackageCurrentPkgPath(true)
assert.Equal(t, err, nil)
hasSubDir, err := hasSubdirInTar(tarPath, "vendor")
assert.Equal(t, err, nil)
assert.Equal(t, hasSubDir, true)

// clean the kcl1
err = os.RemoveAll(kcl1Path)
assert.Equal(t, err, nil)

createKclPkg1()
// package the kcl1 into tar in non-vendor mode.
tarPath, err = kclPkg1.PackageCurrentPkgPath(false)
assert.Equal(t, err, nil)
hasSubDir, err = hasSubdirInTar(tarPath, "vendor")
assert.Equal(t, err, nil)
assert.Equal(t, hasSubDir, false)
}

// check if the tar file contains the subdir
func hasSubdirInTar(tarPath, subdir string) (bool, error) {
f, err := os.Open(tarPath)
if err != nil {
return false, err
}
defer f.Close()

tr := tar.NewReader(f)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if hdr.Typeflag == tar.TypeDir && filepath.Base(hdr.Name) == subdir {
return true, nil
}
}

return false, nil
}
5 changes: 5 additions & 0 deletions pkg/package/test_data/test_pkg_with_vendor/kcl2/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "kcl2"
edition = "0.0.1"
version = "0.0.1"

Empty file.
1 change: 1 addition & 0 deletions pkg/package/test_data/test_pkg_with_vendor/kcl2/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The_first_kcl_program = 'Hello World!'
Loading