Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add mvs to update command #319

Merged
merged 3 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/3rdparty/mvs/mvs.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
for _, target := range targets {
work.Add(target)
}
work.Do(10, func(m module.Version) {
work.Do(1, func(m module.Version) {

var required []module.Version
var err error
Expand Down Expand Up @@ -236,7 +236,7 @@
}
have[m] = true
for _, m1 := range reqCache[m] {
walk(m1)

Check failure on line 239 in pkg/3rdparty/mvs/mvs.go

View workflow job for this annotation

GitHub Actions / Lint checks

Error return value is not checked (errcheck)
}
return nil
}
Expand All @@ -249,7 +249,7 @@
}
m := module.Version{Path: path, Version: max[path]}
min = append(min, m)
walk(m)

Check failure on line 252 in pkg/3rdparty/mvs/mvs.go

View workflow job for this annotation

GitHub Actions / Lint checks

Error return value is not checked (errcheck)
haveBase[path] = true
}
// Now the reverse postorder to bring in anything else.
Expand All @@ -261,7 +261,7 @@
}
if !have[m] {
min = append(min, m)
walk(m)

Check failure on line 264 in pkg/3rdparty/mvs/mvs.go

View workflow job for this annotation

GitHub Actions / Lint checks

Error return value is not checked (errcheck)
}
}
sort.Slice(min, func(i, j int) bool {
Expand Down
23 changes: 23 additions & 0 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,36 @@ func (c *KpmClient) ResolvePkgDepsMetadata(kclPkg *pkg.KclPkg, update bool) erro
return nil
}

func GetReleasesFromSource(sourceType, uri string) ([]string, error) {
var releases []string
var err error

switch sourceType {
case pkg.GIT:
releases, err = git.GetAllGithubReleases(uri)
case pkg.OCI:
releases, err = oci.GetAllImageTags(uri)
}
if err != nil {
return nil, err
}

return releases, nil
}

// UpdateDeps will update the dependencies.
func (c *KpmClient) UpdateDeps(kclPkg *pkg.KclPkg) error {
_, err := c.ResolveDepsMetadataInJsonStr(kclPkg, true)
if err != nil {
return err
}

// update kcl.mod
err = kclPkg.ModFile.StoreModFile()
if err != nil {
return err
}

// Generate file kcl.mod.lock.
if !kclPkg.NoSumCheck {
err := kclPkg.LockDepsVersion()
Expand Down
40 changes: 39 additions & 1 deletion pkg/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"testing"

"github.com/dominikbraun/graph"
"github.com/hashicorp/go-version"
"github.com/otiai10/copy"
"github.com/stretchr/testify/assert"
"golang.org/x/mod/module"
Expand Down Expand Up @@ -815,6 +817,43 @@ func TestParseOciOptionFromString(t *testing.T) {
assert.Equal(t, ociOption.Tag, "test_tag")
}

func TestGetReleasesFromSource(t *testing.T) {
sortVersions := func(versions []string) ([]string, error) {
var vers []*version.Version
for _, raw := range versions {
v, err := version.NewVersion(raw)
if err != nil {
return nil, err
}
vers = append(vers, v)
}
sort.Slice(vers, func(i, j int) bool {
return vers[i].LessThan(vers[j])
})
var res []string
for _, v := range vers {
res = append(res, v.Original())
}
return res, nil
}

releases, err := GetReleasesFromSource(pkg.GIT, "https://github.com/kcl-lang/kpm")
assert.Equal(t, err, nil)
length := len(releases)
assert.True(t, length >= 5)
releasesVersions, err := sortVersions(releases)
assert.Equal(t, err, nil)
assert.Equal(t, releasesVersions[:5], []string{"v0.1.0", "v0.2.0", "v0.2.1", "v0.2.2", "v0.2.3"})

releases, err = GetReleasesFromSource(pkg.OCI, "oci://ghcr.io/kcl-lang/k8s")
assert.Equal(t, err, nil)
length = len(releases)
assert.True(t, length >= 5)
releasesVersions, err = sortVersions(releases)
assert.Equal(t, err, nil)
assert.Equal(t, releasesVersions[:5], []string{"1.14", "1.15", "1.16", "1.17", "1.18"})
}

func TestUpdateWithKclMod(t *testing.T) {
kpmcli, err := NewKpmClient()
assert.Equal(t, err, nil)
Expand Down Expand Up @@ -1469,4 +1508,3 @@ func testRunWithOciDownloader(t *testing.T) {
assert.Equal(t, buf.String(), "downloading 'zong-zhe/helloworld:0.0.3' from 'ghcr.io/zong-zhe/helloworld:0.0.3'\n")
assert.Equal(t, res.GetRawYamlResult(), "The_first_kcl_program: Hello World!")
}

4 changes: 2 additions & 2 deletions pkg/cmd/cmd_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func parseGitRegistryOptions(c *cli.Context) (*opt.RegistryOptions, *reporter.Kp
// parseOciRegistryOptions will parse the oci registry information from user cli inputs.
func parseOciRegistryOptions(c *cli.Context, kpmcli *client.KpmClient) (*opt.RegistryOptions, error) {
ociPkgRef := c.Args().First()
name, version, err := parseOciPkgNameAndVersion(ociPkgRef)
name, version, err := ParseOciPkgNameAndVersion(ociPkgRef)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -243,7 +243,7 @@ func parseLocalPathOptions(c *cli.Context) (*opt.RegistryOptions, *reporter.KpmE

// parseOciPkgNameAndVersion will parse package name and version
// from string "<pkg_name>:<pkg_version>".
func parseOciPkgNameAndVersion(s string) (string, string, error) {
func ParseOciPkgNameAndVersion(s string) (string, string, error) {
parts := strings.Split(s, ":")
if len(parts) == 1 {
return parts[0], "", nil
Expand Down
151 changes: 132 additions & 19 deletions pkg/cmd/cmd_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@
package cmd

import (
"fmt"
"os"
"slices"
"strings"

"github.com/dominikbraun/graph"
"github.com/urfave/cli/v2"
"golang.org/x/mod/module"
"kcl-lang.io/kpm/pkg/client"
"kcl-lang.io/kpm/pkg/env"
"kcl-lang.io/kpm/pkg/mvs"
pkg "kcl-lang.io/kpm/pkg/package"
"kcl-lang.io/kpm/pkg/reporter"
"kcl-lang.io/kpm/pkg/semver"
)

// NewUpdateCmd new a Command for `kpm update`.
Expand Down Expand Up @@ -48,39 +56,144 @@
}
}()

input_paths := c.Args().Slice()
pkgInfos := c.Args().Slice()

pkg_paths := []string{}
if len(input_paths) == 0 {
pwd, err := os.Getwd()
pwd, err := os.Getwd()
if err != nil {
return reporter.NewErrorEvent(reporter.Bug, err, "internal bugs, please contact us to fix it.")
}

kclPkg, err := kpmcli.LoadPkgFromPath(pwd)
if err != nil {
return err
}

globalPkgPath, err := env.GetAbsPkgPath()
if err != nil {
return err
}

err = kclPkg.ValidateKpmHome(globalPkgPath)
if err != (*reporter.KpmEvent)(nil) {
return err
}

var (
modulesToUpgrade []module.Version
modulesToDowngrade []module.Version
)

for _, pkgInfo := range pkgInfos {
Peefy marked this conversation as resolved.
Show resolved Hide resolved
err = GetModulesToUpdate(kclPkg, modulesToUpgrade, modulesToDowngrade, pkgInfo)
if err != nil {
return reporter.NewErrorEvent(reporter.Bug, err, "internal bugs, please contact us to fix it")
reporter.Report(err)
}
pkg_paths = append(pkg_paths, pwd)
} else {
pkg_paths = input_paths
}

for _, pkg_path := range pkg_paths {
kclPkg, err := kpmcli.LoadPkgFromPath(pkg_path)
_, depGraph, err := kpmcli.InitGraphAndDownloadDeps(kclPkg)
if err != nil {
return err
}

reqs := mvs.ReqsGraph{
Graph: depGraph,
KpmClient: kpmcli,
KpmPkg: kclPkg,
}

target := module.Version{Path: kclPkg.GetPkgName(), Version: kclPkg.GetPkgVersion()}
buildList, err := mvs.UpdateBuildList(target, modulesToUpgrade, modulesToDowngrade, &reqs)
if err != nil {
return reporter.NewErrorEvent(reporter.FailedUpdatingBuildList, err, "failed to update build list")
}

// get all the vertices in the graph
modules, err := graph.TopologicalSort(depGraph)
if err != nil {
return reporter.NewErrorEvent(reporter.FailedTopologicalSort, err, "failed to sort the dependencies")
}

kclPkg.ModFile.Dependencies.Deps = make(map[string]pkg.Dependency)
Peefy marked this conversation as resolved.
Show resolved Hide resolved

for _, module := range modules {
err = InsertModuleToDeps(kclPkg, module, target, buildList, reqs)
if err != nil {
return err
}
}

err = kpmcli.UpdateDeps(kclPkg)
if err != nil {
return err
}
return nil
}

// GetModulesToUpdate validates if the packages is present in kcl.mod file and
// find the latest version if version is not specified. Depending on the value of pkgVersion,
// modulesToUpgrade or modulesToDowngrade will be updated.
func GetModulesToUpdate(kclPkg *pkg.KclPkg, modulesToUpgrade []module.Version, modulesToDowngrade []module.Version, pkgInfo string) error {
pkgInfo = strings.TrimSpace(pkgInfo)
pkgName, pkgVersion, err := ParseOciPkgNameAndVersion(pkgInfo)
if err != nil {
return err
}

var dep pkg.Dependency
var ok bool
if dep, ok = kclPkg.Deps[pkgName]; !ok {
return err
}

globalPkgPath, err := env.GetAbsPkgPath()
if pkgVersion == "" {
var releases []string
releases, err = client.GetReleasesFromSource(dep.GetSourceType(), dep.GetDownloadPath())
if err != nil {
return err
return reporter.NewErrorEvent(
reporter.FailedGetReleases,
err,
fmt.Sprintf("failed to get releases for %s", pkgName),
)
}

err = kclPkg.ValidateKpmHome(globalPkgPath)
if err != (*reporter.KpmEvent)(nil) {
return err
pkgVersion, err = semver.LatestCompatibleVersion(releases, dep.Version)
if err != nil {
return reporter.NewErrorEvent(
reporter.FailedSelectLatestCompatibleVersion,
err,
fmt.Sprintf("failed to find the latest version for %s", pkgName),
)
}
}
if pkgVersion < dep.Version {
modulesToDowngrade = append(modulesToDowngrade, module.Version{Path: pkgName, Version: pkgVersion})

Check failure on line 168 in pkg/cmd/cmd_update.go

View workflow job for this annotation

GitHub Actions / Lint checks

ineffectual assignment to modulesToDowngrade (ineffassign)
} else if pkgVersion > dep.Version {
modulesToUpgrade = append(modulesToUpgrade, module.Version{Path: pkgName, Version: pkgVersion})

Check failure on line 170 in pkg/cmd/cmd_update.go

View workflow job for this annotation

GitHub Actions / Lint checks

ineffectual assignment to modulesToUpgrade (ineffassign)
}
return nil
}

err = kpmcli.UpdateDeps(kclPkg)
// InsertModuleToDeps checks whether module is present in the buildList and it is not the same as the target module,
// and inserts it to the dependencies of kclPkg
func InsertModuleToDeps(kclPkg *pkg.KclPkg, module module.Version, target module.Version, buildList []module.Version, reqs mvs.ReqsGraph) (error) {
if module.Path == target.Path || !slices.Contains(buildList, module) {
return nil
}
d := pkg.Dependency{
Name: module.Path,
Version: module.Version,
}
d.FullName = d.GenDepFullName()
_, properties, err := reqs.VertexWithProperties(module)
if err != nil {
return reporter.NewErrorEvent(reporter.FailedGetVertexProperties, err, "failed to get vertex with properties")
}
// there must be one property depending on the download source type
for sourceType, uri := range properties.Attributes {
d.Source, err = pkg.GenSource(sourceType, uri, module.Version)
if err != nil {
return err
return reporter.NewErrorEvent(reporter.FailedGenerateSource, err, "failed to generate source")
}
}
kclPkg.ModFile.Dependencies.Deps[module.Path] = d
return nil
}
}
Loading
Loading