diff --git a/pkg/client/client.go b/pkg/client/client.go index 618e5a4c..348bc643 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -211,14 +211,7 @@ func (c *KpmClient) AcquireDepSum(dep pkg.Dependency) (string, error) { // ResolveDepsIntoMap will calculate the map of kcl package name and local storage path of the external packages. func (c *KpmClient) ResolveDepsIntoMap(kclPkg *pkg.KclPkg) (map[string]string, error) { - var err error - if kclPkg.IsVendorMode() { - err = c.VendorDeps(kclPkg) - } else { - kclPkg, err = c.Update( - WithUpdatedKclPkg(kclPkg), - ) - } + err := c.ResolvePkgDepsMetadata(kclPkg, true) if err != nil { return nil, err } @@ -262,21 +255,16 @@ func (c *KpmClient) getDepStorePath(search_path string, d *pkg.Dependency, isVen // Since redownloads are not triggered if local dependencies exists, // indirect dependencies are also synchronized to the lock file by `lockDeps`. func (c *KpmClient) ResolvePkgDepsMetadata(kclPkg *pkg.KclPkg, update bool) error { + var err error if kclPkg.IsVendorMode() { - // In the vendor mode, the search path is the vendor subdirectory of the current package. - err := c.VendorDeps(kclPkg) - if err != nil { - return err - } + err = c.VendorDeps(kclPkg) } else { - // In the non-vendor mode, the search path is the KCL_PKG_PATH. - err := c.resolvePkgDeps(kclPkg, &kclPkg.Dependencies, update) - if err != nil { - return err - } - + _, err = c.Update( + WithUpdatedKclPkg(kclPkg), + WithOffline(!update), + ) } - return nil + return err } func (c *KpmClient) resolvePkgDeps(kclPkg *pkg.KclPkg, lockDeps *pkg.Dependencies, update bool) error { @@ -426,6 +414,7 @@ func (c *KpmClient) UpdateDeps(kclPkg *pkg.KclPkg) error { if ok, err := features.Enabled(features.SupportMVS); err != nil && ok { _, err = c.Update( WithUpdatedKclPkg(kclPkg), + WithOffline(false), ) if err != nil { return err diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index a7717e36..01ff298c 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -814,10 +814,17 @@ func testResolveMetadataInJsonStr(t *testing.T) { assert.Equal(t, utils.DirExists(vendorDir), false) assert.Equal(t, utils.DirExists(filepath.Join(vendorDir, "flask-demo-kcl-manifests_ade147b")), false) assert.Equal(t, err, nil) - expectedStr := "{\"packages\":{\"flask_demo_kcl_manifests\":{\"name\":\"flask_demo_kcl_manifests\",\"manifest_path\":\"\"}}}" + expectedPath := filepath.Join("not_exist", "flask-demo-kcl-manifests_ade147b") + if runtime.GOOS == "windows" { + expectedPath = strings.ReplaceAll(expectedPath, "\\", "\\\\") + } + expectedStr := fmt.Sprintf( + "{\"packages\":{\"flask_demo_kcl_manifests\":{\"name\":\"flask_demo_kcl_manifests\",\"manifest_path\":\"%s\"}}}", + expectedPath, + ) assert.Equal(t, res, expectedStr) defer func() { - if r := os.RemoveAll(filepath.Join("not_exist", "flask-demo-kcl-manifests_ade147b")); r != nil { + if r := os.RemoveAll(expectedPath); r != nil { err = fmt.Errorf("panic: %v", r) } }() @@ -1146,6 +1153,9 @@ func testMetadataOffline(t *testing.T) { assert.Equal(t, res, "{\"packages\":{}}") content_after_metadata, err := os.ReadFile(kclMod) assert.Equal(t, err, nil) + if runtime.GOOS == "windows" { + uglyContent = []byte(strings.ReplaceAll(string(uglyContent), "\r\n", "\n")) + } assert.Equal(t, string(content_after_metadata), string(uglyContent)) res, err = kpmcli.ResolveDepsMetadataInJsonStr(kclPkg, true) @@ -2253,45 +2263,3 @@ func testPushWithInsecureSkipTLSverify(t *testing.T) { assert.Equal(t, buf.String(), "Called Success\n") } - -func TestIssues(t *testing.T) { - // "kcl-lang/kcl/issue/1760" is the repo where the issue was actually raised and the issue id. - // "testIssue1760" is the test case cover the issue. - RunTestWithGlobalLockAndKpmCli(t, "kcl-lang/kcl/issue/1760", testIssue1760) -} - -func testIssue1760(t *testing.T, kpmcli *KpmClient) { - rootPath := getTestDir("issues") - mainKFilePath := filepath.Join(rootPath, "kcl-lang/kcl/issue/1760", "a", "main.k") - var buf bytes.Buffer - kpmcli.SetLogWriter(&buf) - - res, err := kpmcli.Run( - WithRunSource( - &downloader.Source{ - Local: &downloader.Local{ - Path: mainKFilePath, - }, - }, - ), - ) - - if err != nil { - t.Fatal(err) - } - - assert.Contains(t, - utils.RmNewline(buf.String()), - "downloading 'kcl-lang/fluxcd-source-controller:v1.3.2' from 'ghcr.io/kcl-lang/fluxcd-source-controller:v1.3.2'", - ) - assert.Contains(t, - utils.RmNewline(buf.String()), - "downloading 'kcl-lang/k8s:1.31.2' from 'ghcr.io/kcl-lang/k8s:1.31.2'", - ) - - assert.Contains(t, - utils.RmNewline(buf.String()), - "downloading 'kcl-lang/fluxcd-helm-controller:v1.0.3' from 'ghcr.io/kcl-lang/fluxcd-helm-controller:v1.0.3'", - ) - assert.Equal(t, res.GetRawYamlResult(), "The_first_kcl_program: Hello World!") -} diff --git a/pkg/client/issues_test.go b/pkg/client/issues_test.go new file mode 100644 index 00000000..e2d68ad3 --- /dev/null +++ b/pkg/client/issues_test.go @@ -0,0 +1,209 @@ +package client + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "kcl-lang.io/kpm/pkg/downloader" + "kcl-lang.io/kpm/pkg/features" + pkg "kcl-lang.io/kpm/pkg/package" + "kcl-lang.io/kpm/pkg/utils" +) + +func TestKclIssue1760(t *testing.T) { + testPath := "github.com/kcl-lang/kcl/issues/1760" + testCases := []struct { + name string + setup func() + }{ + { + name: "Default", + setup: func() { + features.Disable(features.SupportNewStorage) + features.Disable(features.SupportMVS) + }, + }, + { + name: "SupportNewStorage", + setup: func() { + features.Enable(features.SupportNewStorage) + features.Disable(features.SupportMVS) + }, + }, + { + name: "SupportMVS", + setup: func() { + features.Disable(features.SupportNewStorage) + features.Enable(features.SupportMVS) + }, + }, + { + name: "SupportNewStorageAndMVS", + setup: func() { + features.Enable(features.SupportNewStorage) + features.Enable(features.SupportMVS) + }, + }, + } + + for _, tc := range testCases { + tc := tc // capture range variable + tc.setup() + + testFunc := func(t *testing.T, kpmcli *KpmClient) { + rootPath := getTestDir("issues") + mainKFilePath := filepath.Join(rootPath, testPath, "a", "main.k") + var buf bytes.Buffer + kpmcli.SetLogWriter(&buf) + + res, err := kpmcli.Run( + WithRunSource( + &downloader.Source{ + Local: &downloader.Local{ + Path: mainKFilePath, + }, + }, + ), + ) + + if err != nil { + t.Fatal(err) + } + + assert.Contains(t, + utils.RmNewline(buf.String()), + "downloading 'kcl-lang/fluxcd-source-controller:v1.3.2' from 'ghcr.io/kcl-lang/fluxcd-source-controller:v1.3.2'", + ) + assert.Contains(t, + utils.RmNewline(buf.String()), + "downloading 'kcl-lang/k8s:1.31.2' from 'ghcr.io/kcl-lang/k8s:1.31.2'", + ) + + assert.Contains(t, + utils.RmNewline(buf.String()), + "downloading 'kcl-lang/fluxcd-helm-controller:v1.0.3' from 'ghcr.io/kcl-lang/fluxcd-helm-controller:v1.0.3'", + ) + assert.Equal(t, res.GetRawYamlResult(), "The_first_kcl_program: Hello World!") + } + + RunTestWithGlobalLockAndKpmCli(t, tc.name, testFunc) + } +} + +func TestKpmIssue550(t *testing.T) { + testPath := "github.com/kcl-lang/kpm/issues/550" + testCases := []struct { + name string + setup func() + expected string + winExpected string + }{ + { + name: "Default", + setup: func() { + features.Disable(features.SupportNewStorage) + features.Disable(features.SupportMVS) + }, + expected: filepath.Join("flask-demo-kcl-manifests_test-branch-without-modfile", "aa", "cc"), + winExpected: filepath.Join("flask-demo-kcl-manifests_test-branch-without-modfile", "aa", "cc"), + }, + { + name: "SupportNewStorage", + setup: func() { + features.Enable(features.SupportNewStorage) + features.Disable(features.SupportMVS) + }, + expected: filepath.Join("git", "src", "200297ed26e4aeb7", "flask-demo-kcl-manifests", "test-branch-without-modfile", "aa", "cc"), + winExpected: filepath.Join("git", "src", "3523a44a55384201", "flask-demo-kcl-manifests", "test-branch-without-modfile", "aa", "cc"), + }, + { + name: "SupportMVS", + setup: func() { + features.Disable(features.SupportNewStorage) + features.Enable(features.SupportMVS) + }, + expected: filepath.Join("flask-demo-kcl-manifests_test-branch-without-modfile", "aa", "cc"), + winExpected: filepath.Join("flask-demo-kcl-manifests_test-branch-without-modfile", "aa", "cc"), + }, + { + name: "SupportNewStorageAndMVS", + setup: func() { + features.Enable(features.SupportNewStorage) + features.Enable(features.SupportMVS) + }, + expected: filepath.Join("git", "src", "200297ed26e4aeb7", "flask-demo-kcl-manifests", "test-branch-without-modfile", "aa", "cc"), + winExpected: filepath.Join("git", "src", "3523a44a55384201", "flask-demo-kcl-manifests", "test-branch-without-modfile", "aa", "cc"), + }, + } + + for _, tc := range testCases { + tc := tc // capture range variable + + tc.setup() + + testFunc := func(t *testing.T, kpmcli *KpmClient) { + rootPath := getTestDir("issues") + modPath := filepath.Join(rootPath, testPath, "pkg") + var buf bytes.Buffer + kpmcli.SetLogWriter(&buf) + + tmpKpmHome, err := os.MkdirTemp("", "") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpKpmHome) + + kpmcli.homePath = tmpKpmHome + + kMod, err := pkg.LoadKclPkgWithOpts( + pkg.WithPath(modPath), + ) + + if err != nil { + t.Fatal(err) + } + + res, err := kpmcli.ResolveDepsMetadataInJsonStr(kMod, true) + + if err != nil { + t.Fatal(err) + } + + expectedPath := filepath.Join(tmpKpmHome, tc.expected) + if runtime.GOOS == "windows" { + expectedPath = filepath.Join(tmpKpmHome, tc.winExpected) + expectedPath = strings.ReplaceAll(expectedPath, "\\", "\\\\") + } + + assert.Equal(t, res, fmt.Sprintf( + `{"packages":{"cc":{"name":"cc","manifest_path":"%s"}}}`, + expectedPath, + )) + + resMap, err := kpmcli.ResolveDepsIntoMap(kMod) + + if err != nil { + t.Fatal(err) + } + fmt.Printf("buf.String(): %v\n", buf.String()) + assert.Contains(t, + utils.RmNewline(buf.String()), + "cloning 'https://github.com/kcl-lang/flask-demo-kcl-manifests.git' with branch 'test-branch-without-modfile'", + ) + assert.Equal(t, len(resMap), 1) + if runtime.GOOS == "windows" { + assert.Equal(t, resMap["cc"], filepath.Join(tmpKpmHome, tc.winExpected)) + } else { + assert.Equal(t, resMap["cc"], filepath.Join(tmpKpmHome, tc.expected)) + } + } + + RunTestWithGlobalLockAndKpmCli(t, tc.name, testFunc) + } +} diff --git a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/README.md b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/README.md similarity index 100% rename from pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/README.md rename to pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/README.md diff --git a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/a/kcl.mod b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/a/kcl.mod similarity index 100% rename from pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/a/kcl.mod rename to pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/a/kcl.mod diff --git a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/a/kcl.mod.lock b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/a/kcl.mod.lock similarity index 76% rename from pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/a/kcl.mod.lock rename to pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/a/kcl.mod.lock index 6a6d847e..252a3083 100644 --- a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/a/kcl.mod.lock +++ b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/a/kcl.mod.lock @@ -19,11 +19,3 @@ reg = "ghcr.io" repo = "kcl-lang/fluxcd-source-controller" oci_tag = "v1.3.2" - [dependencies.k8s] - name = "k8s" - full_name = "k8s_1.31.2" - version = "1.31.2" - sum = "xBZgPsnpVVyWBpahuPQHReeRx28eUHGFoaPeqbct+vs=" - reg = "ghcr.io" - repo = "kcl-lang/k8s" - oci_tag = "1.31.2" diff --git a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/a/main.k b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/a/main.k similarity index 100% rename from pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/a/main.k rename to pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/a/main.k diff --git a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/b/kcl.mod b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/b/kcl.mod similarity index 100% rename from pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/b/kcl.mod rename to pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/b/kcl.mod diff --git a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/b/kcl.mod.lock b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/b/kcl.mod.lock similarity index 61% rename from pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/b/kcl.mod.lock rename to pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/b/kcl.mod.lock index b67bef5c..7fbf5d48 100644 --- a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/b/kcl.mod.lock +++ b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/b/kcl.mod.lock @@ -6,10 +6,3 @@ reg = "ghcr.io" repo = "kcl-lang/fluxcd-source-controller" oci_tag = "v1.3.2" - [dependencies.k8s] - name = "k8s" - full_name = "k8s_1.31.2" - version = "1.31.2" - reg = "ghcr.io" - repo = "kcl-lang/k8s" - oci_tag = "1.31.2" diff --git a/pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/b/main.k b/pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/b/main.k similarity index 100% rename from pkg/client/test_data/issues/kcl-lang/kcl/issue/1760/b/main.k rename to pkg/client/test_data/issues/github.com/kcl-lang/kcl/issues/1760/b/main.k diff --git a/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/README.md b/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/README.md new file mode 100644 index 00000000..85a177d3 --- /dev/null +++ b/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/README.md @@ -0,0 +1,33 @@ +# bug: path information is lost in kcl mod metadata + + +## 1. Minimal reproduce step (Required) + +```shell +kcl mod init demo +cd demo +kcl mod add k8s --git https://github.com/kcl-lang/modules +kcl mod add k8s --rename k8soci +kcl mod add json_merge_patch --git https://github.com/kcl-lang/modules --tag v0.1.0 +kcl mod metadata +``` + +## 2. What did you expect to see? (Required) + +Show the metadata message with local storage path. + +```shell +{"packages":{"json_merge_patch":{"name":"json_merge_patch","manifest_path":""},"k8s":{"name":"k8s","manifest_path":""},"k8soci":{"name":"k8soci","manifest_path":""}}} +``` + +## 3. What did you see instead (Required) + +The real path is empty. + +```shell +{"packages":{"json_merge_patch":{"name":"json_merge_patch","manifest_path":""},"k8s":{"name":"k8s","manifest_path":""},"k8soci":{"name":"k8soci","manifest_path":""}}} +``` + +## 4. What is your KCL components version? (Required) + +v0.11.0-alpha.1 diff --git a/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/kcl.mod b/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/kcl.mod new file mode 100644 index 00000000..e499e150 --- /dev/null +++ b/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "pkg" +edition = "v0.10.0" +version = "0.0.1" + +[dependencies] +cc = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git", branch = "test-branch-without-modfile", version = "0.0.1" } diff --git a/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/kcl.mod.lock b/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/kcl.mod.lock new file mode 100644 index 00000000..a69a0636 --- /dev/null +++ b/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/kcl.mod.lock @@ -0,0 +1,7 @@ +[dependencies] + [dependencies.cc] + name = "cc" + full_name = "cc_0.0.1" + version = "0.0.1" + url = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git" + branch = "test-branch-without-modfile" diff --git a/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/main.k b/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/client/test_data/issues/github.com/kcl-lang/kpm/issues/550/pkg/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/pkg/client/test_data/resolve_metadata/without_package/kcl.mod.lock b/pkg/client/test_data/resolve_metadata/without_package/kcl.mod.lock index 83ace942..935309f6 100644 --- a/pkg/client/test_data/resolve_metadata/without_package/kcl.mod.lock +++ b/pkg/client/test_data/resolve_metadata/without_package/kcl.mod.lock @@ -1,7 +1,7 @@ [dependencies] [dependencies.flask-demo-kcl-manifests] name = "flask-demo-kcl-manifests" - full_name = "flask-demo-kcl-manifests_ade147b" - version = "ade147b" + full_name = "flask_manifests_0.0.1" + version = "0.0.1" url = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git" commit = "ade147b" diff --git a/pkg/client/test_data/test_metadata_offline/ugly.kcl.mod b/pkg/client/test_data/test_metadata_offline/ugly.kcl.mod index ea2fabea..718782c3 100644 --- a/pkg/client/test_data/test_metadata_offline/ugly.kcl.mod +++ b/pkg/client/test_data/test_metadata_offline/ugly.kcl.mod @@ -1,10 +1,4 @@ [package] - - - - - name = "test_metadata_offline" edition = "0.0.1" version = "0.0.1" - diff --git a/pkg/client/test_data/update_with_default_dep/kcl.mod.lock.expect b/pkg/client/test_data/update_with_default_dep/kcl.mod.lock.expect index 358da422..7ed99be2 100644 --- a/pkg/client/test_data/update_with_default_dep/kcl.mod.lock.expect +++ b/pkg/client/test_data/update_with_default_dep/kcl.mod.lock.expect @@ -3,6 +3,7 @@ name = "helloworld" full_name = "helloworld_0.1.2" version = "0.1.2" + sum = "PN0OMEV9M8VGFn1CtA/T3bcgZmMJmOo+RkBrLKIWYeQ=" reg = "ghcr.io" repo = "kcl-lang/helloworld" oci_tag = "0.1.2" diff --git a/pkg/client/update.go b/pkg/client/update.go index dd1f3bc5..acbb0c09 100644 --- a/pkg/client/update.go +++ b/pkg/client/update.go @@ -11,11 +11,20 @@ import ( // Updating a package means iterating all the dependencies of the package // and updating the dependencies and selecting the version of the dependencies by MVS. type UpdateOptions struct { - kpkg *pkg.KclPkg + kpkg *pkg.KclPkg + offline bool } type UpdateOption func(*UpdateOptions) error +// WithOffline sets the offline option to update the package. +func WithOffline(offline bool) UpdateOption { + return func(opts *UpdateOptions) error { + opts.offline = offline + return nil + } +} + // WithUpdatedKclPkg sets the kcl package to be updated. func WithUpdatedKclPkg(kpkg *pkg.KclPkg) UpdateOption { return func(opts *UpdateOptions) error { @@ -100,6 +109,7 @@ func (c *KpmClient) Update(options ...UpdateOption) (*pkg.KclPkg, error) { err := depResolver.Resolve( resolver.WithResolveKclMod(kMod), resolver.WithEnableCache(true), + resolver.WithCachePath(c.homePath), ) if err != nil { diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index 64016bfc..e627b6f8 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -39,10 +39,18 @@ type DownloadOptions struct { credsClient *CredClient // InsecureSkipTLSverify is the flag to skip the verification of the certificate. InsecureSkipTLSverify bool + // Offline is the flag to download the package offline. + Offline bool } type Option func(*DownloadOptions) +func WithOffline(offline bool) Option { + return func(do *DownloadOptions) { + do.Offline = offline + } +} + func WithInsecureSkipTLSverify(insecureSkipTLSverify bool) Option { return func(do *DownloadOptions) { do.InsecureSkipTLSverify = insecureSkipTLSverify @@ -137,6 +145,9 @@ type DepDownloader struct { type GitDownloader struct{} func (d *GitDownloader) LatestVersion(opts *DownloadOptions) (string, error) { + if opts.Offline { + return "", errors.New("offline mode is enabled, the latest version is not supported") + } // TODOļ¼šsupports fetch the latest commit from the git bare repo, // after totally transfer to the new storage. // refer to cargo: https://github.com/rust-lang/cargo/blob/3dedb85a25604bdbbb8d3bf4b03162961a4facd0/crates/cargo-util-schemas/src/core/source_kind.rs#L133 @@ -216,6 +227,10 @@ type OciDownloader struct { } func (d *OciDownloader) LatestVersion(opts *DownloadOptions) (string, error) { + if opts.Offline { + return "", errors.New("offline mode is enabled, the latest version is not supported") + } + // download the package from the OCI registry ociSource := opts.Source.Oci if ociSource == nil { @@ -260,7 +275,6 @@ func NewOciDownloader(platform string) *DepDownloader { } func (d *DepDownloader) Download(opts *DownloadOptions) error { - // create a tmp dir to download the oci package. tmpDir, err := os.MkdirTemp("", "") if err != nil { @@ -447,7 +461,7 @@ func (d *OciDownloader) Download(opts *DownloadOptions) error { return err } } - } else { + } else if !opts.Offline { reporter.ReportMsgTo( fmt.Sprintf( "downloading '%s:%s' from '%s/%s:%s'", @@ -481,7 +495,7 @@ func (d *OciDownloader) Download(opts *DownloadOptions) error { } } } - } else { + } else if !opts.Offline { reporter.ReportMsgTo( fmt.Sprintf( "downloading '%s:%s' from '%s/%s:%s'", @@ -563,14 +577,14 @@ func (d *GitDownloader) Download(opts *DownloadOptions) error { ) // If failed to clone the bare repository from the cache path, // clone the bare repository from the remote git repository, update the cache. - if err != nil { + if err != nil && !opts.Offline { // If the bare repository cache exists, fetch the latest commit from the cache. if utils.DirExists(cacheFullPath) && git.IsGitBareRepo(cacheFullPath) { err := git.Fetch(cacheFullPath) if err != nil { return err } - } else { + } else if !opts.Offline { reporter.ReportMsgTo( fmt.Sprintf("cloning '%s' %s", opts.Source.Git.Url, msg), opts.LogWriter, @@ -608,7 +622,7 @@ func (d *GitDownloader) Download(opts *DownloadOptions) error { } } } - } else { + } else if !opts.Offline { reporter.ReportMsgTo( fmt.Sprintf("cloning '%s' %s", opts.Source.Git.Url, msg), opts.LogWriter, @@ -625,7 +639,7 @@ func (d *GitDownloader) Download(opts *DownloadOptions) error { return err } } - } else { + } else if !opts.Offline { reporter.ReportMsgTo( fmt.Sprintf("cloning '%s' %s", opts.Source.Git.Url, msg), opts.LogWriter, diff --git a/pkg/features/features.go b/pkg/features/features.go index 0116544b..0e69fc49 100644 --- a/pkg/features/features.go +++ b/pkg/features/features.go @@ -5,6 +5,7 @@ package features import ( "os" "strings" + "sync" ) const ( @@ -14,10 +15,13 @@ const ( SupportNewStorage = "SupportNewStorage" ) -var features = map[string]bool{ - SupportMVS: false, - SupportNewStorage: false, -} +var ( + features = map[string]bool{ + SupportMVS: false, + SupportNewStorage: false, + } + mu sync.Mutex +) func init() { // supports the env: export KPM_FEATURE_GATES="SupportMVS=true" @@ -39,6 +43,8 @@ func FeatureGates() map[string]bool { // pkg/runtime/features, so callers won't need to import // both packages for checking whether a feature is enabled. func Enabled(feature string) (bool, error) { + mu.Lock() + defer mu.Unlock() if enabled, ok := features[feature]; ok { return enabled, nil } @@ -48,6 +54,8 @@ func Enabled(feature string) (bool, error) { // Enable enables the specified feature. If the feature is not // present, it's a no-op. func Enable(feature string) { + mu.Lock() + defer mu.Unlock() if _, ok := features[feature]; ok { features[feature] = true } @@ -56,6 +64,8 @@ func Enable(feature string) { // Disable disables the specified feature. If the feature is not // present, it's a no-op. func Disable(feature string) { + mu.Lock() + defer mu.Unlock() if _, ok := features[feature]; ok { features[feature] = false } diff --git a/pkg/resolver/resolver.go b/pkg/resolver/resolver.go index 3d70bdb6..8fcb2a43 100644 --- a/pkg/resolver/resolver.go +++ b/pkg/resolver/resolver.go @@ -27,6 +27,16 @@ type ResolveOptions struct { EnableCache bool // CachePath is the path of the cache. CachePath string + // Offline is the flag to resolve the package offline. + Offline bool +} + +// WithOffline sets the offline option to resolve the package. +func WithOffline(offline bool) ResolveOption { + return func(opts *ResolveOptions) error { + opts.Offline = offline + return nil + } } func WithResolveKclMod(kMod *pkg.KclPkg) ResolveOption { @@ -94,6 +104,7 @@ func (dr *DepsResolver) Resolve(options ...ResolveOption) error { EnableCache: opts.EnableCache, CachePath: cachePath, VisitedSpace: cachePath, + Offline: opts.Offline, }, nil } else if source.IsLocalTarPath() || source.IsLocalTgzPath() { return visitor.NewArchiveVisitor(pkgVisitor), nil diff --git a/pkg/visitor/visitor.go b/pkg/visitor/visitor.go index 447fedf3..b2e97fb9 100644 --- a/pkg/visitor/visitor.go +++ b/pkg/visitor/visitor.go @@ -102,6 +102,7 @@ type RemoteVisitor struct { VisitedSpace string Downloader downloader.Downloader InsecureSkipTLSverify bool + Offline bool } // NewRemoteVisitor creates a new RemoteVisitor.