Skip to content

Commit

Permalink
Merge pull request #146 from zong-zhe/add-run-api
Browse files Browse the repository at this point in the history
feat: create some APIs for command 'kpm run'.
  • Loading branch information
Peefy authored Aug 7, 2023
2 parents 30c41ca + 7d32efb commit 5a53906
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 191 deletions.
188 changes: 188 additions & 0 deletions pkg/api/kpm_run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package api

import (
"os"
"path/filepath"
"strings"

"kcl-lang.io/kpm/pkg/env"
"kcl-lang.io/kpm/pkg/errors"
"kcl-lang.io/kpm/pkg/oci"
"kcl-lang.io/kpm/pkg/opt"
pkg "kcl-lang.io/kpm/pkg/package"
"kcl-lang.io/kpm/pkg/reporter"
"kcl-lang.io/kpm/pkg/runner"
"kcl-lang.io/kpm/pkg/utils"
)

// RunTar will compile the kcl package from a kcl package tar.
func RunTar(tarPath string, entryFiles []string, vendorMode bool, kclArgs string) (string, error) {
absTarPath, err := absTarPath(tarPath)
if err != nil {
return "", err
}
// Extract the tar package to a directory with the same name.
// e.g.
// 'xxx/xxx/xxx/test.tar' will be extracted to the directory 'xxx/xxx/xxx/test'.
destDir := strings.TrimSuffix(absTarPath, filepath.Ext(absTarPath))
err = utils.UnTarDir(absTarPath, destDir)
if err != nil {
return "", err
}

// The directory after extracting the tar package is taken as the root directory of the package,
// and kclvm is called to compile the kcl program under the 'destDir'.
// e.g.
// if the tar path is 'xxx/xxx/xxx/test.tar',
// the 'xxx/xxx/xxx/test' will be taken as the root path of the kcl package to compile.
compileResult, compileErr := RunPkgInPath(destDir, entryFiles, vendorMode, kclArgs)

if compileErr != nil {
return "", compileErr
}
return compileResult, nil
}

const KCL_PKG_TAR = "*.tar"

// RunOci will compile the kcl package from an OCI reference.
func RunOci(ociRef, version string, entryFiles []string, vendorMode bool, kclArgs string) (string, error) {
ociOpts, err := opt.ParseOciOptionFromString(ociRef, version)

if err != nil {
return "", err
}

// 1. Create the temporary directory to pull the tar.
tmpDir, err := os.MkdirTemp("", "")
if err != nil {
return "", errors.InternalBug
}
// clean the temp dir.
defer os.RemoveAll(tmpDir)

localPath := ociOpts.AddStoragePathSuffix(tmpDir)

// 2. Pull the tar.
err = oci.Pull(localPath, ociOpts.Reg, ociOpts.Repo, ociOpts.Tag)

if err != nil {
return "", err
}

// 3.Get the (*.tar) file path.
matches, err := filepath.Glob(filepath.Join(localPath, KCL_PKG_TAR))
if err != nil || len(matches) != 1 {
return "", errors.FailedPull
}

return RunTar(matches[0], entryFiles, vendorMode, kclArgs)
}

// RunPkg will compile current kcl package.
func RunPkg(entryFiles []string, vendorMode bool, kclArgs string) (string, error) {

// If no tar packages specified by "--tar" to run
// kpm will take the current directory ($PWD) as the root of the kcl package and compile.
pwd, err := os.Getwd()

if err != nil {
reporter.ExitWithReport("kpm: internal bug: failed to load working directory")
}

compileResult, err := RunPkgInPath(pwd, entryFiles, vendorMode, kclArgs)
if err != nil {
return "", err
}

return compileResult, nil
}

// RunPkgInPath will load the 'KclPkg' from path 'pkgPath'.
// And run the kcl package with entry file in 'entryFilePath' in 'vendorMode'.
func RunPkgInPath(pkgPath string, entryFilePaths []string, vendorMode bool, kclArgs string) (string, error) {

pkgPath, err := filepath.Abs(pkgPath)
if err != nil {
return "", errors.InternalBug
}

kclPkg, err := pkg.LoadKclPkg(pkgPath)
if err != nil {
return "", errors.FailedToLoadPackage
}

kclPkg.SetVendorMode(vendorMode)

globalPkgPath, err := env.GetAbsPkgPath()
if err != nil {
return "", err
}

err = kclPkg.ValidateKpmHome(globalPkgPath)
if err != (*reporter.KpmEvent)(nil) {
return "", err
}

// Calculate the absolute path of entry file described by '--input'.
compiler := runner.DefaultCompiler()
compiler.SetKclCliArgs(kclArgs)
for _, entryFilePath := range entryFilePaths {
entryFilePath, err = getAbsInputPath(pkgPath, entryFilePath)
if err != nil {
return "", err
}
compiler.AddKFile(entryFilePath)
}

if len(entryFilePaths) == 0 && len(kclPkg.GetEntryKclFilesFromModFile()) == 0 {
compiler.AddKFile(kclPkg.HomePath)
}

// Call the kcl compiler.
compileResult, err := kclPkg.Compile(
globalPkgPath,
compiler,
)

if err != nil {
return "", err
}

return compileResult.GetRawYamlResult(), nil
}

// absTarPath checks whether path 'tarPath' exists and whether path 'tarPath' ends with '.tar'
// And after checking, absTarPath return the abs path for 'tarPath'.
func absTarPath(tarPath string) (string, error) {
absTarPath, err := filepath.Abs(tarPath)
if err != nil {
return "", errors.InternalBug
}

if filepath.Ext(absTarPath) != ".tar" {
return "", errors.InvalidKclPacakgeTar
} else if !utils.DirExists(absTarPath) {
return "", errors.KclPacakgeTarNotFound
}

return absTarPath, nil
}

// getAbsInputPath will return the abs path of the file path described by '--input'.
// If the path exists after 'inputPath' is computed as a full path, it will be returned.
// If not, the kpm checks whether the full path of 'pkgPath/inputPath' exists,
// If the full path of 'pkgPath/inputPath' exists, it will be returned.
// If not, getAbsInputPath returns 'entry file not found' error.
func getAbsInputPath(pkgPath string, inputPath string) (string, error) {
absPath, err := filepath.Abs(filepath.Join(pkgPath, inputPath))
if err != nil {
return "", err
}

if utils.DirExists(absPath) {
return absPath, nil
}

return "", errors.EntryFileNotFound
}
10 changes: 5 additions & 5 deletions pkg/cmd/cmd_run_test.go → pkg/api/kpm_run_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cmd
package api

import (
"os"
Expand Down Expand Up @@ -58,23 +58,23 @@ func TestAbsTarPath(t *testing.T) {

func TestRunPkgInPath(t *testing.T) {
pkgPath := getTestDir("test_run_pkg_in_path")
result, err := runPkgInPath(filepath.Join(pkgPath, "test_kcl"), []string{"main.k"}, false, "")
result, err := RunPkgInPath(filepath.Join(pkgPath, "test_kcl"), []string{"main.k"}, false, "")
assert.Equal(t, err, nil)
expected, _ := os.ReadFile(filepath.Join(pkgPath, "expected"))
assert.Equal(t, utils.RmNewline(string(result)), utils.RmNewline(string(expected)))
}

func TestRunPkgInPathInvalidPath(t *testing.T) {
pkgPath := getTestDir("test_run_pkg_in_path")
result, err := runPkgInPath(filepath.Join(pkgPath, "test_kcl"), []string{"not_exist.k"}, false, "")
result, err := RunPkgInPath(filepath.Join(pkgPath, "test_kcl"), []string{"not_exist.k"}, false, "")
assert.NotEqual(t, err, nil)
assert.Equal(t, err, errors.EntryFileNotFound)
assert.Equal(t, result, "")
}

func TestRunPkgInPathInvalidPkg(t *testing.T) {
pkgPath := getTestDir("test_run_pkg_in_path")
result, err := runPkgInPath(filepath.Join(pkgPath, "invalid_pkg"), []string{"not_exist.k"}, false, "")
result, err := RunPkgInPath(filepath.Join(pkgPath, "invalid_pkg"), []string{"not_exist.k"}, false, "")
assert.NotEqual(t, err, nil)
assert.Equal(t, err, errors.FailedToLoadPackage)
assert.Equal(t, result, "")
Expand All @@ -91,7 +91,7 @@ func TestRunTar(t *testing.T) {
}

expectedResult, _ := os.ReadFile(expectPath)
gotResult, err := runTar(tarPath, []string{""}, true, "")
gotResult, err := RunTar(tarPath, []string{""}, true, "")
assert.Equal(t, err, nil)
assert.Equal(t, utils.RmNewline(string(expectedResult)), utils.RmNewline(gotResult))
assert.Equal(t, utils.DirExists(untarPath), true)
Expand Down
3 changes: 2 additions & 1 deletion pkg/cmd/cmd_pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"path/filepath"

"github.com/urfave/cli/v2"
"kcl-lang.io/kpm/pkg/api"
"kcl-lang.io/kpm/pkg/errors"
"kcl-lang.io/kpm/pkg/oci"
"kcl-lang.io/kpm/pkg/opt"
Expand Down Expand Up @@ -104,7 +105,7 @@ func KpmPull(c *cli.Context) error {
}

// 3. Get the (*.tar) file path.
tarPath := filepath.Join(localPath, KCL_PKG_TAR)
tarPath := filepath.Join(localPath, api.KCL_PKG_TAR)
matches, err := filepath.Glob(tarPath)
if err != nil || len(matches) != 1 {
if err == nil {
Expand Down
12 changes: 12 additions & 0 deletions pkg/cmd/cmd_push_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,24 @@
package cmd

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
pkg "kcl-lang.io/kpm/pkg/package"
)

const testDataDir = "test_data"

func getTestDir(subDir string) string {
pwd, _ := os.Getwd()
testDir := filepath.Join(pwd, testDataDir)
testDir = filepath.Join(testDir, subDir)

return testDir
}

func TestGenDefaultOciUrlForKclPkg(t *testing.T) {
pkgPath := getTestDir("test_gen_oci_url")
kclPkg, err := pkg.LoadKclPkg(pkgPath)
Expand Down
Loading

0 comments on commit 5a53906

Please sign in to comment.