diff --git a/pkg/client/add.go b/pkg/client/add.go new file mode 100644 index 00000000..54c58d1b --- /dev/null +++ b/pkg/client/add.go @@ -0,0 +1,181 @@ +package client + +import ( + "fmt" + "path/filepath" + + "kcl-lang.io/kpm/pkg/downloader" + pkg "kcl-lang.io/kpm/pkg/package" + "kcl-lang.io/kpm/pkg/utils" + "kcl-lang.io/kpm/pkg/visitor" +) + +type AddOptions struct { + // Source is the source of the package to be pulled. + // Including git, oci, local. + Sources []*downloader.Source + KclPkg *pkg.KclPkg +} + +type AddOption func(*AddOptions) error + +func WithAddSource(source *downloader.Source) AddOption { + return func(opts *AddOptions) error { + if opts.Sources == nil { + opts.Sources = make([]*downloader.Source, 0) + } + opts.Sources = append(opts.Sources, source) + return nil + } +} + +func WithAddSources(sources []*downloader.Source) AddOption { + return func(ro *AddOptions) error { + ro.Sources = sources + return nil + } +} + +func WithAddSourceUrl(sourceUrl string) AddOption { + return func(opts *AddOptions) error { + if opts.Sources == nil { + opts.Sources = make([]*downloader.Source, 0) + } + source, err := downloader.NewSourceFromStr(sourceUrl) + if err != nil { + return err + } + opts.Sources = append(opts.Sources, source) + return nil + } +} + +func WithAddSourceUrls(sourceUrls []string) AddOption { + return func(opts *AddOptions) error { + var sources []*downloader.Source + for _, sourceUrl := range sourceUrls { + source, err := downloader.NewSourceFromStr(sourceUrl) + if err != nil { + return err + } + sources = append(sources, source) + } + opts.Sources = sources + return nil + } +} + +func WithAddKclPkg(kclPkg *pkg.KclPkg) AddOption { + return func(opts *AddOptions) error { + opts.KclPkg = kclPkg + return nil + } +} + +func NewAddOptions(opts ...AddOption) *AddOptions { + ao := &AddOptions{} + for _, opt := range opts { + opt(ao) + } + return ao +} + +func (c *KpmClient) Add(options ...AddOption) error { + opts := &AddOptions{} + for _, option := range options { + if err := option(opts); err != nil { + return err + } + } + addedPkg := opts.KclPkg + + visitorSelector := func(source *downloader.Source) (visitor.Visitor, error) { + pkgVisitor := &visitor.PkgVisitor{ + Settings: &c.settings, + LogWriter: c.logWriter, + } + + if source.IsRemote() { + return &visitor.RemoteVisitor{ + PkgVisitor: pkgVisitor, + Downloader: c.DepDownloader, + InsecureSkipTLSverify: c.insecureSkipTLSverify, + EnableCache: true, + CachePath: c.homePath, + VisitedSpace: c.homePath, + }, nil + } else if source.IsLocalTarPath() || source.IsLocalTgzPath() { + return visitor.NewArchiveVisitor(pkgVisitor), nil + } else if source.IsLocalPath() { + return pkgVisitor, nil + } else { + return nil, fmt.Errorf("unsupported source") + } + } + + for _, depSource := range opts.Sources { + // Set the default OCI registry and repo if the source is nil and the package spec is not nil. + if depSource.IsNilSource() && !depSource.ModSpec.IsNil() { + depSource.Oci = &downloader.Oci{ + Reg: c.GetSettings().Conf.DefaultOciRegistry, + Repo: utils.JoinPath(c.GetSettings().Conf.DefaultOciRepo, depSource.ModSpec.Name), + Tag: depSource.ModSpec.Version, + } + } + + var fullSouce *downloader.Source + // Transform the relative path to the full path. + if depSource.IsLocalPath() && !filepath.IsAbs(depSource.Path) { + fullSouce = &downloader.Source{ + ModSpec: depSource.ModSpec, + Local: &downloader.Local{ + Path: filepath.Join(addedPkg.HomePath, depSource.Path), + }, + } + } else { + fullSouce = depSource + } + + visitor, err := visitorSelector(fullSouce) + if err != nil { + return err + } + + // Visit the dependency source + // If the dependency is remote, the visitor will download it to the local. + // If the dependency is already in local cache, the visitor will not download it again. + err = visitor.Visit(fullSouce, func(depPkg *pkg.KclPkg) error { + dep := pkg.Dependency{ + Name: depPkg.ModFile.Pkg.Name, + FullName: depPkg.GetPkgFullName(), + Version: depPkg.ModFile.Pkg.Version, + LocalFullPath: depPkg.HomePath, + Source: *depSource, + } + + // Add the dependency to the kcl.mod file. + if modExistDep, ok := addedPkg.ModFile.Dependencies.Deps.Get(dep.Name); ok { + if less, err := modExistDep.VersionLessThan(&dep); less && err == nil { + addedPkg.ModFile.Dependencies.Deps.Set(dep.Name, dep) + } + } else { + addedPkg.ModFile.Dependencies.Deps.Set(dep.Name, dep) + } + + return nil + }) + if err != nil { + return err + } + } + + // Iterate the dependencies and update the kcl.mod and kcl.mod.lock respectively. + _, err := c.Update( + WithUpdatedKclPkg(addedPkg), + ) + + if err != nil { + return err + } + return nil +} diff --git a/pkg/client/add_test.go b/pkg/client/add_test.go new file mode 100644 index 00000000..f92739b6 --- /dev/null +++ b/pkg/client/add_test.go @@ -0,0 +1,117 @@ +package client + +import ( + "os" + "path/filepath" + "testing" + + "github.com/otiai10/copy" + "github.com/stretchr/testify/assert" + pkg "kcl-lang.io/kpm/pkg/package" + "kcl-lang.io/kpm/pkg/utils" +) + +func testAddWithModSpec(t *testing.T) { + tests := []struct { + name string + pkgSubPath string + sourceUrl string + }{ + { + name: "TestAddOciWithModSpec", + pkgSubPath: "oci", + sourceUrl: "oci://ghcr.io/kcl-lang/helloworld?tag=0.1.4&mod=subhelloworld:0.0.1", + }, + { + name: "TestAddGitWithModSpec", + pkgSubPath: "git", + sourceUrl: "git://github.com/kcl-lang/flask-demo-kcl-manifests.git?commit=8308200&mod=cc:0.0.1", + }, + { + name: "TestAddLocalWithModSpec", + pkgSubPath: filepath.Join("local", "pkg"), + sourceUrl: "../dep?mod=sub:0.0.1", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testDir := getTestDir("add_with_mod_spec") + pkgPath := filepath.Join(testDir, tt.pkgSubPath) + + modbkPath := filepath.Join(pkgPath, "kcl.mod.bk") + modPath := filepath.Join(pkgPath, "kcl.mod") + modExpect := filepath.Join(pkgPath, "kcl.mod.expect") + lockbkPath := filepath.Join(pkgPath, "kcl.mod.lock.bk") + lockPath := filepath.Join(pkgPath, "kcl.mod.lock") + lockExpect := filepath.Join(pkgPath, "kcl.mod.lock.expect") + + err := copy.Copy(modbkPath, modPath) + if err != nil { + t.Fatal(err) + } + + err = copy.Copy(lockbkPath, lockPath) + if err != nil { + t.Fatal(err) + } + + defer func() { + // remove the copied files + err := os.RemoveAll(modPath) + if err != nil { + t.Fatal(err) + } + err = os.RemoveAll(lockPath) + if err != nil { + t.Fatal(err) + } + }() + + kpmcli, err := NewKpmClient() + if err != nil { + t.Fatal(err) + } + + kpkg, err := pkg.LoadKclPkgWithOpts( + pkg.WithPath(pkgPath), + pkg.WithSettings(kpmcli.GetSettings()), + ) + + if err != nil { + t.Fatal(err) + } + + err = kpmcli.Add( + WithAddKclPkg(kpkg), + WithAddSourceUrl(tt.sourceUrl), + ) + + if err != nil { + t.Fatal(err) + } + + expectedMod, err := os.ReadFile(modExpect) + if err != nil { + t.Fatal(err) + } + gotMod, err := os.ReadFile(modPath) + if err != nil { + t.Fatal(err) + } + + expectedLock, err := os.ReadFile(lockExpect) + if err != nil { + t.Fatal(err) + } + + gotLock, err := os.ReadFile(lockPath) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, utils.RmNewline(string(expectedMod)), utils.RmNewline(string(gotMod))) + assert.Equal(t, utils.RmNewline(string(expectedLock)), utils.RmNewline(string(gotLock))) + }) + } +} diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index f974ac3d..206b88b4 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -82,6 +82,7 @@ func TestWithGlobalLock(t *testing.T) { test.RunTestWithGlobalLock(t, "TestDownloadGitWithPackage", testDownloadGitWithPackage) test.RunTestWithGlobalLock(t, "TestModandLockFilesWithGitPackageDownload", testModandLockFilesWithGitPackageDownload) test.RunTestWithGlobalLock(t, "TestDependencyGraph", testDependencyGraph) + test.RunTestWithGlobalLock(t, "testAddWithModSpec", testAddWithModSpec) } // TestDownloadOci test download from oci registry. diff --git a/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.bk b/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.bk new file mode 100644 index 00000000..c894b72b --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.bk @@ -0,0 +1,4 @@ +[package] +name = "git" +edition = "v0.10.0" +version = "0.0.1" diff --git a/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.expect b/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.expect new file mode 100644 index 00000000..0465a74f --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.expect @@ -0,0 +1,7 @@ +[package] +name = "git" +edition = "v0.10.0" +version = "0.0.1" + +[dependencies] +cc = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git", commit = "8308200", version = "0.0.1" } diff --git a/pkg/visitor/test_data/test_visited_space/kcl.mod.lock b/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.lock.bk similarity index 100% rename from pkg/visitor/test_data/test_visited_space/kcl.mod.lock rename to pkg/client/test_data/add_with_mod_spec/git/kcl.mod.lock.bk diff --git a/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.lock.expect b/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.lock.expect new file mode 100644 index 00000000..6d55b3b1 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/git/kcl.mod.lock.expect @@ -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" + commit = "8308200" diff --git a/pkg/visitor/test_data/test_visited_space/main.k b/pkg/client/test_data/add_with_mod_spec/git/main.k similarity index 100% rename from pkg/visitor/test_data/test_visited_space/main.k rename to pkg/client/test_data/add_with_mod_spec/git/main.k diff --git a/pkg/client/test_data/add_with_mod_spec/local/dep/kcl.mod b/pkg/client/test_data/add_with_mod_spec/local/dep/kcl.mod new file mode 100644 index 00000000..65876478 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/local/dep/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "dep" +edition = "v0.10.0" +version = "0.0.1" diff --git a/pkg/client/test_data/add_with_mod_spec/local/dep/kcl.mod.lock b/pkg/client/test_data/add_with_mod_spec/local/dep/kcl.mod.lock new file mode 100644 index 00000000..e69de29b diff --git a/pkg/client/test_data/add_with_mod_spec/local/dep/main.k b/pkg/client/test_data/add_with_mod_spec/local/dep/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/local/dep/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/pkg/client/test_data/add_with_mod_spec/local/dep/sub/kcl.mod b/pkg/client/test_data/add_with_mod_spec/local/dep/sub/kcl.mod new file mode 100644 index 00000000..d4fbb209 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/local/dep/sub/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "sub" +edition = "v0.10.0" +version = "0.0.1" diff --git a/pkg/client/test_data/add_with_mod_spec/local/dep/sub/kcl.mod.lock b/pkg/client/test_data/add_with_mod_spec/local/dep/sub/kcl.mod.lock new file mode 100644 index 00000000..e69de29b diff --git a/pkg/client/test_data/add_with_mod_spec/local/dep/sub/main.k b/pkg/client/test_data/add_with_mod_spec/local/dep/sub/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/local/dep/sub/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.bk b/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.bk new file mode 100644 index 00000000..2fc4b3ae --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.bk @@ -0,0 +1,4 @@ +[package] +name = "pkg" +edition = "v0.10.0" +version = "0.0.1" diff --git a/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.expect b/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.expect new file mode 100644 index 00000000..2f012ac7 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.expect @@ -0,0 +1,7 @@ +[package] +name = "pkg" +edition = "v0.10.0" +version = "0.0.1" + +[dependencies] +sub = { path = "../dep", version = "0.0.1" } diff --git a/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.lock.bk b/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.lock.bk new file mode 100644 index 00000000..e69de29b diff --git a/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.lock.expect b/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.lock.expect new file mode 100644 index 00000000..0ccdffef --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/local/pkg/kcl.mod.lock.expect @@ -0,0 +1,5 @@ +[dependencies] + [dependencies.sub] + name = "sub" + full_name = "sub_0.0.1" + version = "0.0.1" diff --git a/pkg/client/test_data/add_with_mod_spec/local/pkg/main.k b/pkg/client/test_data/add_with_mod_spec/local/pkg/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/local/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/add_with_mod_spec/oci/kcl.mod.bk b/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.bk new file mode 100644 index 00000000..a16eafb7 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.bk @@ -0,0 +1,6 @@ +[package] +name = "oci" +edition = "v0.10.0" +version = "0.0.1" + +[dependencies] diff --git a/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.expect b/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.expect new file mode 100644 index 00000000..b5004265 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.expect @@ -0,0 +1,7 @@ +[package] +name = "oci" +edition = "v0.10.0" +version = "0.0.1" + +[dependencies] +subhelloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.4", version = "0.0.1" } diff --git a/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.lock.bk b/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.lock.bk new file mode 100644 index 00000000..e69de29b diff --git a/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.lock.expect b/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.lock.expect new file mode 100644 index 00000000..eb72fe2d --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/oci/kcl.mod.lock.expect @@ -0,0 +1,8 @@ +[dependencies] + [dependencies.subhelloworld] + name = "subhelloworld" + full_name = "subhelloworld_0.0.1" + version = "0.0.1" + reg = "ghcr.io" + repo = "kcl-lang/helloworld" + oci_tag = "0.1.4" diff --git a/pkg/client/test_data/add_with_mod_spec/oci/main.k b/pkg/client/test_data/add_with_mod_spec/oci/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/oci/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/pkg/client/update.go b/pkg/client/update.go index d994561b..775e5de3 100644 --- a/pkg/client/update.go +++ b/pkg/client/update.go @@ -106,7 +106,12 @@ func (c *KpmClient) Update(options ...UpdateOption) (*pkg.KclPkg, error) { depSource = &dep.Source } - err := depResolver.Resolve( + err := resolverFunc(&dep, kpkg) + if err != nil { + return nil, err + } + + err = depResolver.Resolve( resolver.WithEnableCache(true), resolver.WithSource(depSource), ) diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index a5e277e7..cb33df3f 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -6,7 +6,6 @@ import ( "io" "os" "path/filepath" - "strings" v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/otiai10/copy" @@ -143,29 +142,7 @@ func (d *DepDownloader) Download(opts DownloadOptions) error { localPath := opts.LocalPath cacheFullPath := opts.CachePath if ok, err := features.Enabled(features.SupportNewStorage); err == nil && !ok && opts.EnableCache { - // TODO: After the new local storage structure is complete, - // this section should be replaced with the new storage structure instead of the cache path according to the /. - // https://github.com/kcl-lang/kpm/issues/384 - var pkgFullName string - if opts.Source.Oci != nil && len(opts.Source.Oci.Tag) != 0 { - pkgFullName = fmt.Sprintf("%s_%s", filepath.Base(opts.Source.Oci.Repo), opts.Source.Oci.Tag) - } - - if opts.Source.Git != nil && len(opts.Source.Git.Tag) != 0 { - gitUrl := strings.TrimSuffix(opts.Source.Git.Url, filepath.Ext(opts.Source.Git.Url)) - pkgFullName = fmt.Sprintf("%s_%s", filepath.Base(gitUrl), opts.Source.Git.Tag) - } - if opts.Source.Git != nil && len(opts.Source.Git.Branch) != 0 { - gitUrl := strings.TrimSuffix(opts.Source.Git.Url, filepath.Ext(opts.Source.Git.Url)) - pkgFullName = fmt.Sprintf("%s_%s", filepath.Base(gitUrl), opts.Source.Git.Branch) - } - if opts.Source.Git != nil && len(opts.Source.Git.Commit) != 0 { - gitUrl := strings.TrimSuffix(opts.Source.Git.Url, filepath.Ext(opts.Source.Git.Url)) - pkgFullName = fmt.Sprintf("%s_%s", filepath.Base(gitUrl), opts.Source.Git.Commit) - } - - cacheFullPath = filepath.Join(opts.CachePath, pkgFullName) - + cacheFullPath = filepath.Join(opts.CachePath, opts.Source.LocalPath()) if utils.DirExists(cacheFullPath) && utils.DirExists(filepath.Join(cacheFullPath, constants.KCL_MOD)) { // copy the cache to the local path if cacheFullPath != opts.LocalPath { @@ -220,11 +197,13 @@ func (d *DepDownloader) Download(opts DownloadOptions) error { return err } - if opts.EnableCache { + if ok, err := features.Enabled(features.SupportNewStorage); err == nil && !ok && opts.EnableCache { // Enable the cache, update the dependency package to the cache path. - err := copy.Copy(localPath, cacheFullPath) - if err != nil { - return err + if cacheFullPath != localPath { + err := copy.Copy(localPath, cacheFullPath) + if err != nil { + return err + } } } diff --git a/pkg/downloader/source.go b/pkg/downloader/source.go index 71718eba..8625597b 100644 --- a/pkg/downloader/source.go +++ b/pkg/downloader/source.go @@ -88,7 +88,7 @@ func (source *Source) IsLocalTgzPath() bool { } func (source *Source) IsRemote() bool { - return source.Git != nil || source.Oci != nil || !source.ModSpec.IsNil() + return source.Local == nil && (source.Git != nil || source.Oci != nil || !source.ModSpec.IsNil()) } func (source *Source) IsPackaged() bool { @@ -400,20 +400,23 @@ func (source *Source) FromString(sourceStr string) error { if err != nil { return err } + queryParams := sourceUrl.Query() + queryParams.Del(constants.Mod) + sourceUrl.RawQuery = queryParams.Encode() } if sourceUrl.Scheme == constants.GitScheme || sourceUrl.Scheme == constants.SshScheme { source.Git = &Git{} - source.Git.FromString(sourceStr) + source.Git.FromString(sourceUrl.String()) } else if sourceUrl.Scheme == constants.OciScheme { source.Oci = &Oci{} - source.Oci.FromString(sourceStr) + source.Oci.FromString(sourceUrl.String()) } else if sourceUrl.Scheme == constants.DefaultOciScheme { source.ModSpec = &ModSpec{} - source.ModSpec.FromString(sourceStr) + source.ModSpec.FromString(sourceUrl.String()) } else { source.Local = &Local{} - source.Local.FromString(sourceStr) + source.Local.FromString(sourceUrl.String()) } return nil @@ -641,3 +644,28 @@ func (o *Oci) Hash() (string, error) { func (l *Local) Hash() (string, error) { return utils.ShortHash(l.Path) } + +func (s *Source) LocalPath() string { + // TODO: After the new local storage structure is complete, + // this section should be replaced with the new storage structure instead of the cache path according to the /. + // https://github.com/kcl-lang/kpm/issues/384 + var path string + if s.Oci != nil && len(s.Oci.Tag) != 0 { + path = fmt.Sprintf("%s_%s", filepath.Base(s.Oci.Repo), s.Oci.Tag) + } + + if s.Git != nil && len(s.Git.Tag) != 0 { + gitUrl := strings.TrimSuffix(s.Git.Url, filepath.Ext(s.Git.Url)) + path = fmt.Sprintf("%s_%s", filepath.Base(gitUrl), s.Git.Tag) + } + if s.Git != nil && len(s.Git.Branch) != 0 { + gitUrl := strings.TrimSuffix(s.Git.Url, filepath.Ext(s.Git.Url)) + path = fmt.Sprintf("%s_%s", filepath.Base(gitUrl), s.Git.Branch) + } + if s.Git != nil && len(s.Git.Commit) != 0 { + gitUrl := strings.TrimSuffix(s.Git.Url, filepath.Ext(s.Git.Url)) + path = fmt.Sprintf("%s_%s", filepath.Base(gitUrl), s.Git.Commit) + } + + return path +} diff --git a/pkg/visitor/test_data/test_visited_space/kcl.mod b/pkg/visitor/test_data/test_visited_space/helloworld_0.1.2/kcl.mod similarity index 100% rename from pkg/visitor/test_data/test_visited_space/kcl.mod rename to pkg/visitor/test_data/test_visited_space/helloworld_0.1.2/kcl.mod diff --git a/pkg/visitor/test_data/test_visited_space/helloworld_0.1.2/kcl.mod.lock b/pkg/visitor/test_data/test_visited_space/helloworld_0.1.2/kcl.mod.lock new file mode 100644 index 00000000..e69de29b diff --git a/pkg/visitor/test_data/test_visited_space/helloworld_0.1.2/main.k b/pkg/visitor/test_data/test_visited_space/helloworld_0.1.2/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/visitor/test_data/test_visited_space/helloworld_0.1.2/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/pkg/visitor/visitor.go b/pkg/visitor/visitor.go index e6e23332..0ef5dc2a 100644 --- a/pkg/visitor/visitor.go +++ b/pkg/visitor/visitor.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "os" + "path/filepath" "github.com/google/uuid" "kcl-lang.io/kpm/pkg/downloader" @@ -38,6 +39,13 @@ func (pv *PkgVisitor) Visit(s *downloader.Source, v visitFunc) error { return err } + if !s.ModSpec.IsNil() { + modPath, err = utils.FindPackage(modPath, s.ModSpec.Name) + if err != nil { + return err + } + } + kclPkg, err := pkg.LoadKclPkgWithOpts( pkg.WithPath(modPath), pkg.WithSettings(pv.Settings), @@ -109,22 +117,22 @@ func (rv *RemoteVisitor) Visit(s *downloader.Source, v visitFunc) error { return fmt.Errorf("source is not remote") } - var visitedSpace string + var modPath string var err error if len(rv.VisitedSpace) != 0 { - visitedSpace = rv.VisitedSpace + modPath = filepath.Join(rv.VisitedSpace, s.LocalPath()) } else { tmpDir, err := os.MkdirTemp("", "") if err != nil { return err } - visitedSpace = tmpDir + modPath = tmpDir defer os.RemoveAll(tmpDir) } - if !utils.DirExists(visitedSpace) { - err := os.MkdirAll(visitedSpace, 0755) + if !utils.DirExists(modPath) { + err := os.MkdirAll(modPath, 0755) if err != nil { return err } @@ -136,7 +144,7 @@ func (rv *RemoteVisitor) Visit(s *downloader.Source, v visitFunc) error { } err = rv.Downloader.Download(*downloader.NewDownloadOptions( - downloader.WithLocalPath(visitedSpace), + downloader.WithLocalPath(modPath), downloader.WithSource(*s), downloader.WithLogWriter(rv.LogWriter), downloader.WithSettings(*rv.Settings), @@ -149,16 +157,15 @@ func (rv *RemoteVisitor) Visit(s *downloader.Source, v visitFunc) error { if err != nil { return err } - pkgPath := visitedSpace if !s.ModSpec.IsNil() { - pkgPath, err = utils.FindPackage(visitedSpace, s.ModSpec.Name) + modPath, err = utils.FindPackage(modPath, s.ModSpec.Name) if err != nil { return err } } kclPkg, err := pkg.LoadKclPkgWithOpts( - pkg.WithPath(pkgPath), + pkg.WithPath(modPath), pkg.WithSettings(rv.Settings), ) if err != nil { diff --git a/pkg/visitor/visitor_test.go b/pkg/visitor/visitor_test.go index 1d12a0cf..714f779b 100644 --- a/pkg/visitor/visitor_test.go +++ b/pkg/visitor/visitor_test.go @@ -120,7 +120,7 @@ func TestVisitedSpace(t *testing.T) { err = remotePkgVisitor.Visit(source, func(pkg *pkg.KclPkg) error { assert.Equal(t, pkg.GetPkgName(), "helloworld") assert.Equal(t, pkg.GetPkgVersion(), "0.1.2") - assert.Equal(t, pkg.HomePath, filepath.Join(remotePkgVisitor.VisitedSpace)) + assert.Equal(t, pkg.HomePath, filepath.Join(remotePkgVisitor.VisitedSpace, source.LocalPath())) return nil }) assert.NilError(t, err)