diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 455894e7..0dab4754 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -36,15 +36,11 @@ import ( ) func TestWithGlobalLock(t *testing.T) { - test.RunTestWithGlobalLock(t, "TestUpdateWithKclMod", testUpdateWithKclMod) - test.RunTestWithGlobalLock(t, "TestUpdateWithKclModlock", testUpdateWithKclModlock) - test.RunTestWithGlobalLock(t, "TestUpdateWithNoSumCheck", testUpdateWithNoSumCheck) test.RunTestWithGlobalLock(t, "TestAddWithDiffVersionNoSumCheck", testAddWithDiffVersionNoSumCheck) test.RunTestWithGlobalLock(t, "TestAddWithDiffVersionWithSumCheck", testAddWithDiffVersionWithSumCheck) test.RunTestWithGlobalLock(t, "TestDownloadOci", testDownloadOci) test.RunTestWithGlobalLock(t, "TestAddWithOciDownloader", testAddWithOciDownloader) test.RunTestWithGlobalLock(t, "TestAddDefaultRegistryDep", testAddDefaultRegistryDep) - test.RunTestWithGlobalLock(t, "TestUpdateDefaultRegistryDep", testUpdateDefaultRegistryDep) test.RunTestWithGlobalLock(t, "TestAddWithNoSumCheck", testAddWithNoSumCheck) test.RunTestWithGlobalLock(t, "TestAddWithGitCommit", testAddWithGitCommit) test.RunTestWithGlobalLock(t, "TestDependenciesOrder", testDependenciesOrder) @@ -52,7 +48,6 @@ func TestWithGlobalLock(t *testing.T) { test.RunTestWithGlobalLock(t, "TestResolveMetadataInJsonStrWithPackage", testResolveMetadataInJsonStrWithPackage) test.RunTestWithGlobalLock(t, "TestResolveMetadataInJsonStr", testResolveMetadataInJsonStr) test.RunTestWithGlobalLock(t, "testPackageCurrentPkgPath", testPackageCurrentPkgPath) - test.RunTestWithGlobalLock(t, "TestUpdateKclModAndLock", testUpdateKclModAndLock) test.RunTestWithGlobalLock(t, "TestResolveDepsWithOnlyKclMod", testResolveDepsWithOnlyKclMod) test.RunTestWithGlobalLock(t, "TestResolveDepsVendorMode", testResolveDepsVendorMode) test.RunTestWithGlobalLock(t, "TestCompileWithEntryFile", testCompileWithEntryFile) @@ -436,17 +431,14 @@ func TestInitEmptyPkg(t *testing.T) { assert.Equal(t, testKclPkg.ModFile.Pkg.Edition, runner.GetKclVersion()) } -func testUpdateKclModAndLock(t *testing.T) { +func testUpdateKclModAndLock(t *testing.T, kpmcli *KpmClient) { testDir := initTestDir("test_data_add_deps") // Init an empty package kclPkg := pkg.NewKclPkg(&opt.InitOptions{ Name: "test_add_deps", InitPath: testDir, }) - - kpmcli, err := NewKpmClient() - assert.Equal(t, err, nil) - err = kpmcli.InitEmptyPkg(&kclPkg) + err := kpmcli.InitEmptyPkg(&kclPkg) assert.Equal(t, err, nil) dep := pkg.Dependency{ @@ -1060,14 +1052,11 @@ func TestGetReleasesFromSource(t *testing.T) { assert.Equal(t, releasesVersions[:5], []string{"1.14", "1.14.1", "1.15", "1.15.1", "1.16"}) } -func testUpdateWithKclMod(t *testing.T) { - kpmcli, err := NewKpmClient() - assert.Equal(t, err, nil) - +func testUpdateWithKclMod(t *testing.T, kpmcli *KpmClient) { testDir := getTestDir("test_update") src_testDir := filepath.Join(testDir, "test_update_kcl_mod") dest_testDir := filepath.Join(testDir, "test_update_kcl_mod_tmp") - err = copy.Copy(src_testDir, dest_testDir) + err := copy.Copy(src_testDir, dest_testDir) assert.Equal(t, err, nil) kclPkg, err := kpmcli.LoadPkgFromPath(dest_testDir) @@ -1092,14 +1081,11 @@ func testUpdateWithKclMod(t *testing.T) { }() } -func testUpdateWithKclModlock(t *testing.T) { - kpmcli, err := NewKpmClient() - assert.Equal(t, err, nil) - +func testUpdateWithKclModlock(t *testing.T, kpmcli *KpmClient) { testDir := getTestDir("test_update") src_testDir := filepath.Join(testDir, "test_update_kcl_mod_lock") dest_testDir := filepath.Join(testDir, "test_update_kcl_mod_lock_tmp") - err = copy.Copy(src_testDir, dest_testDir) + err := copy.Copy(src_testDir, dest_testDir) assert.Equal(t, err, nil) kclPkg, err := pkg.LoadKclPkg(dest_testDir) @@ -1197,10 +1183,8 @@ func testAddWithNoSumCheck(t *testing.T) { }() } -func testUpdateWithNoSumCheck(t *testing.T) { +func testUpdateWithNoSumCheck(t *testing.T, kpmcli *KpmClient) { pkgPath := getTestDir("test_update_no_sum_check") - kpmcli, err := NewKpmClient() - assert.Equal(t, err, nil) var buf bytes.Buffer kpmcli.SetLogWriter(&buf) @@ -1695,7 +1679,7 @@ func verifyFileContent(t *testing.T, filePath, expectPath string) { assert.Equal(t, contentStr, expectContentStr) } -func testUpdateDefaultRegistryDep(t *testing.T) { +func testUpdateDefaultRegistryDep(t *testing.T, kpmcli *KpmClient) { pkgPath := getTestDir("update_with_default_dep") pkgWithSumCheckPathModBak := filepath.Join(pkgPath, "kcl.mod.bak") @@ -1711,9 +1695,6 @@ func testUpdateDefaultRegistryDep(t *testing.T) { err = copy.Copy(pkgWithSumCheckPathModLockBak, pkgWithSumCheckPathModLock) assert.Equal(t, err, nil) - kpmcli, err := NewKpmClient() - assert.Equal(t, err, nil) - kclPkg, err := kpmcli.LoadPkgFromPath(pkgPath) assert.Equal(t, err, nil) diff --git a/pkg/client/graph.go b/pkg/client/graph.go index 2ae01f96..f9ff3f51 100644 --- a/pkg/client/graph.go +++ b/pkg/client/graph.go @@ -2,11 +2,9 @@ package client import ( "fmt" - "path/filepath" "github.com/dominikbraun/graph" "golang.org/x/mod/module" - "kcl-lang.io/kpm/pkg/downloader" pkg "kcl-lang.io/kpm/pkg/package" "kcl-lang.io/kpm/pkg/resolver" ) @@ -156,37 +154,13 @@ func (c *KpmClient) Graph(opts ...GraphOption) (*DepGraph, error) { } depResolver.ResolveFuncs = append(depResolver.ResolveFuncs, resolverFunc) - for _, depName := range modDeps.Keys() { - dep, ok := modDeps.Get(depName) - if !ok { - return nil, fmt.Errorf("failed to get dependency %s", depName) - } - - // Check if the dependency is a local path and it is not an absolute path. - // If it is not an absolute path, transform the path to an absolute path. - var depSource *downloader.Source - if dep.Source.IsLocalPath() && !filepath.IsAbs(dep.Source.Local.Path) { - depSource = &downloader.Source{ - Local: &downloader.Local{ - Path: filepath.Join(kMod.HomePath, dep.Source.Local.Path), - }, - } - } else { - depSource = &dep.Source - } + err := depResolver.Resolve( + resolver.WithEnableCache(true), + resolver.WithResolveKclMod(kMod), + ) - err := resolverFunc(&dep, kMod) - if err != nil { - return nil, err - } - - err = depResolver.Resolve( - resolver.WithEnableCache(true), - resolver.WithSource(depSource), - ) - if err != nil { - return nil, err - } + if err != nil { + return nil, err } return dGraph, nil diff --git a/pkg/client/update.go b/pkg/client/update.go index 775e5de3..2a7d88e9 100644 --- a/pkg/client/update.go +++ b/pkg/client/update.go @@ -2,9 +2,7 @@ package client import ( "fmt" - "path/filepath" - "kcl-lang.io/kpm/pkg/downloader" pkg "kcl-lang.io/kpm/pkg/package" "kcl-lang.io/kpm/pkg/resolver" ) @@ -34,16 +32,16 @@ func (c *KpmClient) Update(options ...UpdateOption) (*pkg.KclPkg, error) { } } - kpkg := opts.kpkg - if kpkg == nil { + kMod := opts.kpkg + if kMod == nil { return nil, fmt.Errorf("kcl package is nil") } - modDeps := kpkg.ModFile.Dependencies.Deps + modDeps := kMod.ModFile.Dependencies.Deps if modDeps == nil { return nil, fmt.Errorf("kcl.mod dependencies is nil") } - lockDeps := kpkg.Dependencies.Deps + lockDeps := kMod.Dependencies.Deps if lockDeps == nil { return nil, fmt.Errorf("kcl.mod.lock dependencies is nil") } @@ -58,72 +56,49 @@ func (c *KpmClient) Update(options ...UpdateOption) (*pkg.KclPkg, error) { } // ResolveFunc is the function for resolving each dependency when traversing the dependency graph. resolverFunc := func(dep *pkg.Dependency, parentPkg *pkg.KclPkg) error { + selectedModDep := dep // Check if the dependency exists in the mod file. if existDep, exist := modDeps.Get(dep.Name); exist { // if the dependency exists in the mod file, // check the version and select the greater one. - if less, err := existDep.VersionLessThan(dep); less && err == nil { - kpkg.ModFile.Dependencies.Deps.Set(dep.Name, *dep) + if less, err := dep.VersionLessThan(&existDep); less && err == nil { + selectedModDep = &existDep } // if the dependency does not exist in the mod file, // the dependency is a indirect dependency. // it will be added to the kcl.mod.lock file not the kcl.mod file. + kMod.ModFile.Dependencies.Deps.Set(dep.Name, *selectedModDep) } + + selectedDep := dep // Check if the dependency exists in the lock file. if existDep, exist := lockDeps.Get(dep.Name); exist { // If the dependency exists in the lock file, // check the version and select the greater one. - if less, err := existDep.VersionLessThan(dep); less && err == nil { - kpkg.Dependencies.Deps.Set(dep.Name, *dep) + if less, err := dep.VersionLessThan(&existDep); less && err == nil { + selectedDep = &existDep } - } else { - // if the dependency does not exist in the lock file, - // the dependency is a new dependency and will be added to the lock file. - kpkg.Dependencies.Deps.Set(dep.Name, *dep) } + selectedDep.LocalFullPath = dep.LocalFullPath + kMod.Dependencies.Deps.Set(dep.Name, *selectedDep) return nil } depResolver.ResolveFuncs = append(depResolver.ResolveFuncs, resolverFunc) - // Iterate all the dependencies of the package in kcl.mod and resolve each dependency. - for _, depName := range modDeps.Keys() { - dep, ok := modDeps.Get(depName) - if !ok { - return nil, fmt.Errorf("failed to get dependency %s", depName) - } - - // Check if the dependency is a local path and it is not an absolute path. - // If it is not an absolute path, transform the path to an absolute path. - var depSource *downloader.Source - if dep.Source.IsLocalPath() && !filepath.IsAbs(dep.Source.Local.Path) { - depSource = &downloader.Source{ - Local: &downloader.Local{ - Path: filepath.Join(kpkg.HomePath, dep.Source.Local.Path), - }, - } - } else { - depSource = &dep.Source - } - - err := resolverFunc(&dep, kpkg) - if err != nil { - return nil, err - } + err := depResolver.Resolve( + resolver.WithResolveKclMod(kMod), + resolver.WithEnableCache(true), + ) - err = depResolver.Resolve( - resolver.WithEnableCache(true), - resolver.WithSource(depSource), - ) - if err != nil { - return nil, err - } + if err != nil { + return nil, err } - err := kpkg.UpdateModAndLockFile() + err = kMod.UpdateModAndLockFile() if err != nil { return nil, err } - return kpkg, nil + return kMod, nil } diff --git a/pkg/client/update_test.go b/pkg/client/update_test.go index 3bb411fc..701a115a 100644 --- a/pkg/client/update_test.go +++ b/pkg/client/update_test.go @@ -12,12 +12,17 @@ import ( ) func TestUpdate(t *testing.T) { + RunTestWithGlobalLockAndKpmCli(t, "TestUpdateWithKclMod", testUpdateWithKclMod) + RunTestWithGlobalLockAndKpmCli(t, "TestUpdateWithKclModlock", testUpdateWithKclModlock) + RunTestWithGlobalLockAndKpmCli(t, "TestUpdateWithNoSumCheck", testUpdateWithNoSumCheck) + RunTestWithGlobalLockAndKpmCli(t, "TestUpdateDefaultRegistryDep", testUpdateDefaultRegistryDep) + RunTestWithGlobalLockAndKpmCli(t, "TestUpdateWithKclModAndLock", testUpdateKclModAndLock) + RunTestWithGlobalLockAndKpmCli(t, "TestUpdate", testUpdate) +} + +func testUpdate(t *testing.T, kpmcli *KpmClient) { features.Enable(features.SupportMVS) testDir := getTestDir("test_update_with_mvs") - kpmcli, err := NewKpmClient() - if err != nil { - t.Fatal(err) - } updates := []struct { name string diff --git a/pkg/resolver/resolver.go b/pkg/resolver/resolver.go index 8b8a2bd4..3d70bdb6 100644 --- a/pkg/resolver/resolver.go +++ b/pkg/resolver/resolver.go @@ -21,15 +21,21 @@ type ResolveOption func(*ResolveOptions) error type resolveFunc func(dep *pkg.Dependency, parentPkg *pkg.KclPkg) error type ResolveOptions struct { - // Source is the source of the package to be pulled. - // Including git, oci, local. - Source *downloader.Source + // kMod is the module to be resolved. + kMod *pkg.KclPkg // EnableCache is the flag to enable the cache during the resolving the remote package. EnableCache bool // CachePath is the path of the cache. CachePath string } +func WithResolveKclMod(kMod *pkg.KclPkg) ResolveOption { + return func(opts *ResolveOptions) error { + opts.kMod = kMod + return nil + } +} + // WithEnableCache sets the flag to enable the cache during the resolving the remote package. func WithEnableCache(enableCache bool) ResolveOption { return func(opts *ResolveOptions) error { @@ -46,26 +52,6 @@ func WithCachePath(cachePath string) ResolveOption { } } -// WithSource sets the source of the package to be resolved. -func WithSource(source *downloader.Source) ResolveOption { - return func(opts *ResolveOptions) error { - opts.Source = source - return nil - } -} - -// WithResolveSourceUrl sets the source of the package to be resolved by the source url. -func WithSourceUrl(sourceUrl string) ResolveOption { - return func(opts *ResolveOptions) error { - source, err := downloader.NewSourceFromStr(sourceUrl) - if err != nil { - return err - } - opts.Source = source - return nil - } -} - // DepsResolver is the resolver for resolving dependencies. type DepsResolver struct { DefaultCachePath string @@ -84,7 +70,6 @@ func (dr *DepsResolver) Resolve(options ...ResolveOption) error { return err } } - // visitorSelectorFunc selects the visitor for the source. // For remote source, it will use the RemoteVisitor and enable the cache. // For local source, it will use the PkgVisitor. @@ -128,70 +113,65 @@ func (dr *DepsResolver) Resolve(options ...ResolveOption) error { } } - // visitFunc is the function for visiting the package. - // It will traverse the dependency graph and visit each dependency by source. - visitFunc := func(kclPkg *pkg.KclPkg) error { - // Traverse the all dependencies of the package. - for _, depKey := range kclPkg.ModFile.Deps.Keys() { - dep, ok := kclPkg.ModFile.Deps.Get(depKey) - if !ok { - break - } + kMod := opts.kMod + if kMod == nil { + return fmt.Errorf("kcl module is nil") + } - // Get the dependency source. - var depSource downloader.Source - // If the dependency source is a local path and the path is not absolute, transform the path to absolute path. - if dep.Source.IsLocalPath() && !filepath.IsAbs(dep.Source.Path) { - depSource = downloader.Source{ - Local: &downloader.Local{ - Path: filepath.Join(kclPkg.HomePath, dep.Source.Path), - }, - } - } else { - depSource = dep.Source - } + modDeps := kMod.ModFile.Dependencies.Deps + if modDeps == nil { + return fmt.Errorf("kcl.mod dependencies is nil") + } - // Get the visitor for the dependency source. - visitor, err := visitorSelectorFunc(&depSource) - if err != nil { - return err - } + for _, depName := range modDeps.Keys() { + dep, ok := modDeps.Get(depName) + if !ok { + return fmt.Errorf("failed to get dependency %s", depName) + } - // Visit this dependency and current package as the parent package. - err = visitor.Visit(&depSource, - func(childPkg *pkg.KclPkg) error { - for _, resolveFunc := range dr.ResolveFuncs { - err := resolveFunc(&dep, kclPkg) - if err != nil { - return err - } - } - return nil + // Check if the dependency is a local path and it is not an absolute path. + // If it is not an absolute path, transform the path to an absolute path. + var depSource *downloader.Source + if dep.Source.IsLocalPath() && !filepath.IsAbs(dep.Source.Local.Path) { + depSource = &downloader.Source{ + Local: &downloader.Local{ + Path: filepath.Join(kMod.HomePath, dep.Source.Local.Path), }, - ) - - if err != nil { - return err + ModSpec: dep.Source.ModSpec, } + } else { + depSource = &dep.Source + } - // Recursively resolve the dependencies of the dependency. + depVisitor, err := visitorSelectorFunc(depSource) + if err != nil { + return err + } + + err = depVisitor.Visit(depSource, func(kclMod *pkg.KclPkg) error { + dep.FromKclPkg(kclMod) + for _, resolveFunc := range dr.ResolveFuncs { + err := resolveFunc(&dep, kMod) + if err != nil { + return err + } + } err = dr.Resolve( - WithSource(&depSource), + WithResolveKclMod(kclMod), WithEnableCache(opts.EnableCache), WithCachePath(opts.CachePath), ) if err != nil { return err } - } - return nil - } + return nil + }) - visitor, err := visitorSelectorFunc(opts.Source) - if err != nil { - return err + if err != nil { + return err + } } - return visitor.Visit(opts.Source, visitFunc) + return nil } diff --git a/pkg/resolver/resolver_test.go b/pkg/resolver/resolver_test.go index 18c7e396..8df37b23 100644 --- a/pkg/resolver/resolver_test.go +++ b/pkg/resolver/resolver_test.go @@ -47,9 +47,17 @@ func TestResolver(t *testing.T) { }}, } + kMod, err := pkg.LoadKclPkgWithOpts( + pkg.WithPath(pkgPath), + ) + + if err != nil { + t.Fatal(err) + } + err = resolver.Resolve( WithEnableCache(true), - WithSourceUrl(pkgPath), + WithResolveKclMod(kMod), ) if err != nil {