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..8795c12d 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,50 @@ 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. } + + 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.ModFile.Dependencies.Deps.Set(dep.Name, *selectedModDep) + 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) - } + err := depResolver.Resolve( + resolver.WithResolveKclMod(kMod), + resolver.WithEnableCache(true), + ) - // 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.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/resolver/resolver.go b/pkg/resolver/resolver.go index 8b8a2bd4..a42f8ddd 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,64 @@ 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 } + } 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 {