From 7d32efb192e43ba2dd5d06f30fbc854d23c9dfc6 Mon Sep 17 00:00:00 2001 From: zongz Date: Fri, 4 Aug 2023 14:26:01 +0800 Subject: [PATCH] feat: create some APIs for command 'kpm run'. --- pkg/api/kpm_run.go | 188 +++++++++++++++++ .../cmd_run_test.go => api/kpm_run_test.go} | 10 +- .../test_abs_input/test_input_outside | 0 .../test_abs_input/test_pkg_path/test_input | 0 .../test_data/test_check_tar_path/test.tar | Bin .../test_data/test_run_pkg_in_path/expected | 0 .../test_run_pkg_in_path/test_kcl/kcl.mod | 0 .../test_kcl/kcl.mod.lock | 0 .../test_run_pkg_in_path/test_kcl/main.k | 0 .../test_data/test_run_tar_in_path/expected | 0 .../test_data/test_run_tar_in_path/test.tar | Bin pkg/cmd/cmd_pull.go | 3 +- pkg/cmd/cmd_push_test.go | 12 ++ pkg/cmd/cmd_run.go | 189 +----------------- 14 files changed, 211 insertions(+), 191 deletions(-) create mode 100644 pkg/api/kpm_run.go rename pkg/{cmd/cmd_run_test.go => api/kpm_run_test.go} (91%) rename pkg/{cmd => api}/test_data/test_abs_input/test_input_outside (100%) rename pkg/{cmd => api}/test_data/test_abs_input/test_pkg_path/test_input (100%) rename pkg/{cmd => api}/test_data/test_check_tar_path/test.tar (100%) rename pkg/{cmd => api}/test_data/test_run_pkg_in_path/expected (100%) rename pkg/{cmd => api}/test_data/test_run_pkg_in_path/test_kcl/kcl.mod (100%) rename pkg/{cmd => api}/test_data/test_run_pkg_in_path/test_kcl/kcl.mod.lock (100%) rename pkg/{cmd => api}/test_data/test_run_pkg_in_path/test_kcl/main.k (100%) rename pkg/{cmd => api}/test_data/test_run_tar_in_path/expected (100%) rename pkg/{cmd => api}/test_data/test_run_tar_in_path/test.tar (100%) diff --git a/pkg/api/kpm_run.go b/pkg/api/kpm_run.go new file mode 100644 index 00000000..d59ab8ba --- /dev/null +++ b/pkg/api/kpm_run.go @@ -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 +} diff --git a/pkg/cmd/cmd_run_test.go b/pkg/api/kpm_run_test.go similarity index 91% rename from pkg/cmd/cmd_run_test.go rename to pkg/api/kpm_run_test.go index 72851fd0..b75fee00 100644 --- a/pkg/cmd/cmd_run_test.go +++ b/pkg/api/kpm_run_test.go @@ -1,4 +1,4 @@ -package cmd +package api import ( "os" @@ -58,7 +58,7 @@ 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))) @@ -66,7 +66,7 @@ func TestRunPkgInPath(t *testing.T) { 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, "") @@ -74,7 +74,7 @@ func TestRunPkgInPathInvalidPath(t *testing.T) { 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, "") @@ -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) diff --git a/pkg/cmd/test_data/test_abs_input/test_input_outside b/pkg/api/test_data/test_abs_input/test_input_outside similarity index 100% rename from pkg/cmd/test_data/test_abs_input/test_input_outside rename to pkg/api/test_data/test_abs_input/test_input_outside diff --git a/pkg/cmd/test_data/test_abs_input/test_pkg_path/test_input b/pkg/api/test_data/test_abs_input/test_pkg_path/test_input similarity index 100% rename from pkg/cmd/test_data/test_abs_input/test_pkg_path/test_input rename to pkg/api/test_data/test_abs_input/test_pkg_path/test_input diff --git a/pkg/cmd/test_data/test_check_tar_path/test.tar b/pkg/api/test_data/test_check_tar_path/test.tar similarity index 100% rename from pkg/cmd/test_data/test_check_tar_path/test.tar rename to pkg/api/test_data/test_check_tar_path/test.tar diff --git a/pkg/cmd/test_data/test_run_pkg_in_path/expected b/pkg/api/test_data/test_run_pkg_in_path/expected similarity index 100% rename from pkg/cmd/test_data/test_run_pkg_in_path/expected rename to pkg/api/test_data/test_run_pkg_in_path/expected diff --git a/pkg/cmd/test_data/test_run_pkg_in_path/test_kcl/kcl.mod b/pkg/api/test_data/test_run_pkg_in_path/test_kcl/kcl.mod similarity index 100% rename from pkg/cmd/test_data/test_run_pkg_in_path/test_kcl/kcl.mod rename to pkg/api/test_data/test_run_pkg_in_path/test_kcl/kcl.mod diff --git a/pkg/cmd/test_data/test_run_pkg_in_path/test_kcl/kcl.mod.lock b/pkg/api/test_data/test_run_pkg_in_path/test_kcl/kcl.mod.lock similarity index 100% rename from pkg/cmd/test_data/test_run_pkg_in_path/test_kcl/kcl.mod.lock rename to pkg/api/test_data/test_run_pkg_in_path/test_kcl/kcl.mod.lock diff --git a/pkg/cmd/test_data/test_run_pkg_in_path/test_kcl/main.k b/pkg/api/test_data/test_run_pkg_in_path/test_kcl/main.k similarity index 100% rename from pkg/cmd/test_data/test_run_pkg_in_path/test_kcl/main.k rename to pkg/api/test_data/test_run_pkg_in_path/test_kcl/main.k diff --git a/pkg/cmd/test_data/test_run_tar_in_path/expected b/pkg/api/test_data/test_run_tar_in_path/expected similarity index 100% rename from pkg/cmd/test_data/test_run_tar_in_path/expected rename to pkg/api/test_data/test_run_tar_in_path/expected diff --git a/pkg/cmd/test_data/test_run_tar_in_path/test.tar b/pkg/api/test_data/test_run_tar_in_path/test.tar similarity index 100% rename from pkg/cmd/test_data/test_run_tar_in_path/test.tar rename to pkg/api/test_data/test_run_tar_in_path/test.tar diff --git a/pkg/cmd/cmd_pull.go b/pkg/cmd/cmd_pull.go index 94ab3c93..d828d1e7 100644 --- a/pkg/cmd/cmd_pull.go +++ b/pkg/cmd/cmd_pull.go @@ -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" @@ -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 { diff --git a/pkg/cmd/cmd_push_test.go b/pkg/cmd/cmd_push_test.go index 25676e2e..521c5313 100644 --- a/pkg/cmd/cmd_push_test.go +++ b/pkg/cmd/cmd_push_test.go @@ -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) diff --git a/pkg/cmd/cmd_run.go b/pkg/cmd/cmd_run.go index 4649fd70..04f12bf4 100644 --- a/pkg/cmd/cmd_run.go +++ b/pkg/cmd/cmd_run.go @@ -4,19 +4,10 @@ package cmd import ( "fmt" - "os" - "path/filepath" - "strings" "github.com/urfave/cli/v2" - "kcl-lang.io/kpm/pkg/env" + "kcl-lang.io/kpm/pkg/api" "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" ) // NewRunCmd new a Command for `kpm run`. @@ -54,16 +45,16 @@ func NewRunCmd() *cli.Command { pkgWillBeCompiled := c.Args().First() // 'kpm run' compile the current package undor '$pwd'. if len(pkgWillBeCompiled) == 0 { - compileResult, err := runPkg(c.StringSlice(FLAG_INPUT), c.Bool(FLAG_VENDOR), c.String(FLAG_KCL)) + compileResult, err := api.RunPkg(c.StringSlice(FLAG_INPUT), c.Bool(FLAG_VENDOR), c.String(FLAG_KCL)) if err != nil { return err } fmt.Println(compileResult) } else { // 'kpm run ' compile the kcl package from the . - compileResult, err := runTar(pkgWillBeCompiled, c.StringSlice(FLAG_INPUT), c.Bool(FLAG_VENDOR), c.String(FLAG_KCL)) + compileResult, err := api.RunTar(pkgWillBeCompiled, c.StringSlice(FLAG_INPUT), c.Bool(FLAG_VENDOR), c.String(FLAG_KCL)) if err == errors.InvalidKclPacakgeTar { - compileResult, err = runOci(pkgWillBeCompiled, c.String(FLAG_TAG), c.StringSlice(FLAG_INPUT), c.Bool(FLAG_VENDOR), c.String(FLAG_KCL)) + compileResult, err = api.RunOci(pkgWillBeCompiled, c.String(FLAG_TAG), c.StringSlice(FLAG_INPUT), c.Bool(FLAG_VENDOR), c.String(FLAG_KCL)) if err != nil { return err } @@ -76,175 +67,3 @@ func NewRunCmd() *cli.Command { }, } } - -// 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 -}