diff --git a/go.mod b/go.mod index 5645d7bc..3e8ea547 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/elliotchance/orderedmap/v2 v2.2.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -153,6 +154,7 @@ require ( require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/elliotchance/orderedmap v1.6.0 github.com/go-git/go-git/v5 v5.11.0 github.com/gofrs/flock v0.8.1 github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 diff --git a/go.sum b/go.sum index 0905f7d5..819f7c54 100644 --- a/go.sum +++ b/go.sum @@ -317,6 +317,10 @@ github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucV github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elliotchance/orderedmap v1.6.0 h1:xjn+kbbKXeDq6v9RVE+WYwRbYfAZKvlWfcJNxM8pvEw= +github.com/elliotchance/orderedmap v1.6.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= +github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk= +github.com/elliotchance/orderedmap/v2 v2.2.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= diff --git a/pkg/api/kpm_pkg_test.go b/pkg/api/kpm_pkg_test.go index b088d9e5..b53d2b8e 100644 --- a/pkg/api/kpm_pkg_test.go +++ b/pkg/api/kpm_pkg_test.go @@ -23,9 +23,9 @@ func TestPackageApi(t *testing.T) { assert.Equal(t, pkg.GetPkgName(), "kcl_pkg") assert.Equal(t, pkg.GetVersion(), "0.0.1") assert.Equal(t, pkg.GetEdition(), "0.0.1") - assert.Equal(t, len(pkg.GetDependencies().Deps), 1) + assert.Equal(t, pkg.GetDependencies().Deps.Len(), 1) - dep := pkg.GetDependencies().Deps["k8s"] + dep, _ := pkg.GetDependencies().Deps.Get("k8s") assert.Equal(t, dep.Name, "k8s") assert.Equal(t, dep.FullName, "k8s_1.27") assert.Equal(t, dep.Version, "1.27") @@ -63,7 +63,7 @@ func TestApiGetDependenciesInModFile(t *testing.T) { pkg_path := filepath.Join(getTestDir("test_get_mod_deps"), "kcl_pkg") pkg, err := GetKclPackage(pkg_path) assert.Equal(t, err, nil) - dep := pkg.GetDependenciesInModFile().Deps["k8s"] + dep, _ := pkg.GetDependenciesInModFile().Deps.Get("k8s") assert.Equal(t, dep.Name, "k8s") assert.Equal(t, dep.FullName, "k8s_1.27") assert.Equal(t, dep.Version, "1.27") diff --git a/pkg/client/client.go b/pkg/client/client.go index c2042e37..4cdf4756 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -10,6 +10,7 @@ import ( "github.com/BurntSushi/toml" "github.com/dominikbraun/graph" + "github.com/elliotchance/orderedmap" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/otiai10/copy" "golang.org/x/mod/module" @@ -117,9 +118,10 @@ func (c *KpmClient) LoadPkgFromPath(pkgPath string) (*pkg.KclPkg, error) { } // Align the dependencies between kcl.mod and kcl.mod.lock. - for name, dep := range modFile.Dependencies.Deps { + for _, name := range modFile.Dependencies.Deps.Keys() { + dep, _ := modFile.Dependencies.Deps.Get(name) if dep.Local != nil { - if ldep, ok := deps.Deps[name]; ok { + if ldep, ok := deps.Deps.Get(name); ok { var localFullPath string if filepath.IsAbs(dep.Local.Path) { localFullPath = dep.Local.Path @@ -132,8 +134,8 @@ func (c *KpmClient) LoadPkgFromPath(pkgPath string) (*pkg.KclPkg, error) { ldep.LocalFullPath = localFullPath dep.LocalFullPath = localFullPath ldep.Source = dep.Source - deps.Deps[name] = ldep - modFile.Dependencies.Deps[name] = dep + deps.Deps.Set(name, ldep) + modFile.Dependencies.Deps.Set(name, dep) } } } @@ -155,7 +157,7 @@ func (c *KpmClient) LoadModFile(pkgPath string) (*pkg.ModFile, error) { modFile.HomePath = pkgPath if modFile.Dependencies.Deps == nil { - modFile.Dependencies.Deps = make(map[string]pkg.Dependency) + modFile.Dependencies.Deps = orderedmap.NewOrderedMap[string, pkg.Dependency]() } err = c.FillDependenciesInfo(modFile) if err != nil { @@ -172,13 +174,14 @@ func (c *KpmClient) LoadLockDeps(pkgPath string) (*pkg.Dependencies, error) { return nil, err } - for name, dep := range deps.Deps { + for _, name := range deps.Deps.Keys() { + dep, _ := deps.Deps.Get(name) sum, err := c.AcquireDepSum(dep) if err != nil { return nil, err } dep.Sum = sum - deps.Deps[name] = dep + deps.Deps.Set(name, dep) } return deps, nil @@ -237,7 +240,8 @@ func (c *KpmClient) ResolveDepsIntoMap(kclPkg *pkg.KclPkg) (map[string]string, e return nil, err } var pkgMap map[string]string = make(map[string]string) - for _, d := range depMetadatas.Deps { + for _, k := range depMetadatas.Deps.Keys() { + d, _ := depMetadatas.Deps.Get(k) pkgMap[d.GetAliasName()] = d.GetLocalFullPath(kclPkg.HomePath) } @@ -309,15 +313,17 @@ func (c *KpmClient) resolvePkgDeps(kclPkg *pkg.KclPkg, lockDeps *pkg.Dependencie // alian the dependencies between kcl.mod and kcl.mod.lock // clean the dependencies in kcl.mod.lock which not in kcl.mod // clean the dependencies in kcl.mod.lock and kcl.mod which have different version - for name, dep := range kclPkg.Dependencies.Deps { - modDep, ok := kclPkg.ModFile.Dependencies.Deps[name] + for _, name := range kclPkg.Dependencies.Deps.Keys() { + dep, _ := kclPkg.Dependencies.Deps.Get(name) + modDep, ok := kclPkg.ModFile.Dependencies.Deps.Get(name) if !ok || !dep.Equals(modDep) { - delete(kclPkg.Dependencies.Deps, name) + kclPkg.Dependencies.Deps.Delete(name) } } // add the dependencies in kcl.mod which not in kcl.mod.lock - for name, d := range kclPkg.ModFile.Dependencies.Deps { - if _, ok := kclPkg.Dependencies.Deps[name]; !ok { + for _, name := range kclPkg.ModFile.Dependencies.Deps.Keys() { + d, _ := kclPkg.ModFile.Dependencies.Deps.Get(name) + if _, ok := kclPkg.Dependencies.Deps.Get(name); !ok { if len(d.Version) == 0 { reporter.ReportMsgTo( fmt.Sprintf("adding '%s'", name), @@ -330,7 +336,7 @@ func (c *KpmClient) resolvePkgDeps(kclPkg *pkg.KclPkg, lockDeps *pkg.Dependencie ) } - kclPkg.Dependencies.Deps[name] = d + kclPkg.Dependencies.Deps.Set(name, d) } } } else { @@ -339,7 +345,8 @@ func (c *KpmClient) resolvePkgDeps(kclPkg *pkg.KclPkg, lockDeps *pkg.Dependencie kclPkg.Dependencies.Deps = kclPkg.ModFile.Dependencies.Deps } - for name, d := range kclPkg.Dependencies.Deps { + for _, name := range kclPkg.Dependencies.Deps.Keys() { + d, _ := kclPkg.Dependencies.Deps.Get(name) searchPath = c.getDepStorePath(kclPkg.HomePath, &d, kclPkg.IsVendorMode()) depPath := searchPath // if the dependency is not exist @@ -388,8 +395,8 @@ func (c *KpmClient) resolvePkgDeps(kclPkg *pkg.KclPkg, lockDeps *pkg.Dependencie if err != nil { return err } - kclPkg.Dependencies.Deps[name] = d - lockDeps.Deps[name] = d + kclPkg.Dependencies.Deps.Set(name, d) + lockDeps.Deps.Set(name, d) } // Generate file kcl.mod.lock. @@ -746,19 +753,19 @@ func (c *KpmClient) AddDepWithOpts(kclPkg *pkg.KclPkg, opt *opt.AddOptions) (*pk // 3. update the kcl.mod and kcl.mod.lock. if opt.NewPkgName != "" { // update the kcl.mod with NewPkgName - tempDeps := kclPkg.ModFile.Dependencies.Deps[d.Name] + tempDeps, _ := kclPkg.ModFile.Dependencies.Deps.Get(d.Name) tempDeps.Name = opt.NewPkgName - kclPkg.ModFile.Dependencies.Deps[d.Name] = tempDeps + kclPkg.ModFile.Dependencies.Deps.Set(d.Name, tempDeps) // update the kcl.mod.lock with NewPkgName - tempDeps = kclPkg.Dependencies.Deps[d.Name] + tempDeps, _ = kclPkg.Dependencies.Deps.Get(d.Name) tempDeps.Name = opt.NewPkgName tempDeps.FullName = opt.NewPkgName + "_" + tempDeps.Version - kclPkg.Dependencies.Deps[d.Name] = tempDeps + kclPkg.Dependencies.Deps.Set(d.Name, tempDeps) // update the key of kclPkg.Dependencies.Deps from d.Name to opt.NewPkgName - kclPkg.Dependencies.Deps[opt.NewPkgName] = kclPkg.Dependencies.Deps[d.Name] - delete(kclPkg.Dependencies.Deps, d.Name) + kclPkg.Dependencies.Deps.Set(opt.NewPkgName, kclPkg.Dependencies.Deps.GetOrDefault(d.Name, pkg.TestPkgDependency)) + kclPkg.Dependencies.Deps.Delete(d.Name) } err = kclPkg.UpdateModAndLockFile() @@ -788,9 +795,9 @@ func (c *KpmClient) AddDepToPkg(kclPkg *pkg.KclPkg, d *pkg.Dependency) error { // Some field will be empty when the dependency is add from CLI. // For avoiding re-download the dependency, just complete part of the fields not all of them. - if !kclPkg.ModFile.Dependencies.Deps[d.Name].Equals(*d) { + if !kclPkg.ModFile.Dependencies.Deps.GetOrDefault(d.Name, pkg.TestPkgDependency).Equals(*d) { // the dep passed on the cli is different from the kcl.mod. - kclPkg.ModFile.Dependencies.Deps[d.Name] = *d + kclPkg.ModFile.Dependencies.Deps.Set(d.Name, *d) } // download all the dependencies. @@ -851,9 +858,10 @@ func (c *KpmClient) VendorDeps(kclPkg *pkg.KclPkg) error { return err } - lockDeps := make([]pkg.Dependency, 0, len(kclPkg.Dependencies.Deps)) + lockDeps := make([]pkg.Dependency, 0, kclPkg.Dependencies.Deps.Len()) - for _, d := range kclPkg.Dependencies.Deps { + for _, k := range kclPkg.Dependencies.Deps.Keys() { + d, _ := kclPkg.Dependencies.Deps.Get(k) lockDeps = append(lockDeps, d) } @@ -938,12 +946,13 @@ func (c *KpmClient) FillDepInfo(dep *pkg.Dependency, homepath string) error { // FillDependenciesInfo will fill registry information for all dependencies in a kcl.mod. func (c *KpmClient) FillDependenciesInfo(modFile *pkg.ModFile) error { - for k, v := range modFile.Deps { + for _, k := range modFile.Deps.Keys() { + v, _ := modFile.Deps.Get(k) err := c.FillDepInfo(&v, modFile.HomePath) if err != nil { return err } - modFile.Deps[k] = v + modFile.Deps.Set(k, v) } return nil } @@ -1483,22 +1492,23 @@ func (c *KpmClient) dependencyExistsLocal(searchPath string, dep *pkg.Dependency func (c *KpmClient) DownloadDeps(deps *pkg.Dependencies, lockDeps *pkg.Dependencies, depGraph graph.Graph[module.Version, module.Version], pkghome string, parent module.Version) (*pkg.Dependencies, error) { newDeps := pkg.Dependencies{ - Deps: make(map[string]pkg.Dependency), + Deps: orderedmap.NewOrderedMap[string, pkg.Dependency](), } // Traverse all dependencies in kcl.mod - for _, d := range deps.Deps { + for _, k := range deps.Deps.Keys() { + d, _ := deps.Deps.Get(k) if len(d.Name) == 0 { return nil, errors.InvalidDependency } existDep, err := c.dependencyExistsLocal(pkghome, &d) if existDep != nil && err == nil { - newDeps.Deps[d.Name] = *existDep + newDeps.Deps.Set(d.Name, *existDep) continue } - expectedSum := lockDeps.Deps[d.Name].Sum + expectedSum := lockDeps.Deps.GetOrDefault(d.Name, pkg.TestPkgDependency).Sum // Clean the cache if len(c.homePath) == 0 || len(d.FullName) == 0 { return nil, errors.InternalBug @@ -1516,7 +1526,7 @@ func (c *KpmClient) DownloadDeps(deps *pkg.Dependencies, lockDeps *pkg.Dependenc return nil, err } - if lockedDep.Oci != nil && lockedDep.Equals(lockDeps.Deps[d.Name]) { + if lockedDep.Oci != nil && lockedDep.Equals(lockDeps.Deps.GetOrDefault(d.Name, pkg.TestPkgDependency)) { if !c.noSumCheck && expectedSum != "" && lockedDep.Sum != "" && lockedDep.Sum != expectedSum { @@ -1528,17 +1538,18 @@ func (c *KpmClient) DownloadDeps(deps *pkg.Dependencies, lockDeps *pkg.Dependenc } } - newDeps.Deps[d.Name] = *lockedDep + newDeps.Deps.Set(d.Name, *lockedDep) // After downloading the dependency in kcl.mod, update the dep into to the kcl.mod // Only the direct dependencies are updated to kcl.mod. - deps.Deps[d.Name] = *lockedDep + deps.Deps.Set(d.Name, *lockedDep) } // necessary to make a copy as when we are updating kcl.mod in below for loop // then newDeps.Deps gets updated and range gets an extra value to iterate through // this messes up the dependency graph - newDepsCopy := make(map[string]pkg.Dependency) - for k, v := range newDeps.Deps { + newDepsCopy := orderedmap.NewOrderedMap[string, pkg.Dependency]() + for _, k := range newDeps.Deps.Keys() { + v, _ := newDeps.Deps.Get(k) newDepsCopy[k] = v } @@ -1587,17 +1598,19 @@ func (c *KpmClient) DownloadDeps(deps *pkg.Dependencies, lockDeps *pkg.Dependenc return nil, err } - for _, d := range nested.Deps { - if _, ok := newDeps.Deps[d.Name]; !ok { - newDeps.Deps[d.Name] = d + for _, k := range nested.Deps.Keys() { + d, _ := nested.Deps.Get(k) + if _, ok := newDeps.Deps.Get(d.Name); !ok { + newDeps.Deps.Set(d.Name, d) } } } // After each dependency is downloaded, update all the new deps to kcl.mod.lock. // No matter whether the dependency is directly or indirectly. - for k, v := range newDeps.Deps { - lockDeps.Deps[k] = v + for _, k := range newDeps.Deps.Keys() { + v, _ := newDeps.Deps.Get(k) + lockDeps.Deps.Set(k, v) } return &newDeps, nil diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index d0df4502..d3ff1148 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -15,6 +15,7 @@ import ( "testing" "github.com/dominikbraun/graph" + "github.com/elliotchance/orderedmap/v2" "github.com/hashicorp/go-version" "github.com/otiai10/copy" "github.com/stretchr/testify/assert" @@ -305,11 +306,11 @@ func TestUpdateKclModAndLock(t *testing.T) { }, } - kclPkg.Dependencies.Deps["oci_test"] = oci_dep - kclPkg.ModFile.Dependencies.Deps["oci_test"] = oci_dep + kclPkg.Dependencies.Deps.Set("oci_test", oci_dep) + kclPkg.ModFile.Dependencies.Deps.Set("oci_test", oci_dep) - kclPkg.Dependencies.Deps["test"] = dep - kclPkg.ModFile.Dependencies.Deps["test"] = dep + kclPkg.Dependencies.Deps.Set("test", dep) + kclPkg.ModFile.Dependencies.Deps.Set("test", dep) err = kclPkg.ModFile.StoreModFile() assert.Equal(t, err, nil) @@ -321,8 +322,8 @@ func TestUpdateKclModAndLock(t *testing.T) { if gotKclMod, err := os.ReadFile(filepath.Join(testDir, "kcl.mod")); os.IsNotExist(err) { t.Errorf("failed to find kcl.mod.") } else { - assert.Equal(t, len(kclPkg.Dependencies.Deps), 2) - assert.Equal(t, len(kclPkg.ModFile.Deps), 2) + assert.Equal(t, kclPkg.Dependencies.Deps.Len(), 2) + assert.Equal(t, kclPkg.ModFile.Deps.Len(), 2) expectKclMod, _ := os.ReadFile(filepath.Join(expectDir, "kcl.mod")) expectKclModReverse, _ := os.ReadFile(filepath.Join(expectDir, "kcl.reverse.mod")) @@ -343,8 +344,8 @@ func TestUpdateKclModAndLock(t *testing.T) { if gotKclModLock, err := os.ReadFile(filepath.Join(testDir, "kcl.mod.lock")); os.IsNotExist(err) { t.Errorf("failed to find kcl.mod.lock.") } else { - assert.Equal(t, len(kclPkg.Dependencies.Deps), 2) - assert.Equal(t, len(kclPkg.ModFile.Deps), 2) + assert.Equal(t, kclPkg.Dependencies.Deps.Len(), 2) + assert.Equal(t, kclPkg.ModFile.Deps.Len(), 2) expectKclModLock, _ := os.ReadFile(filepath.Join(expectDir, "kcl.mod.lock")) expectKclModLockReverse, _ := os.ReadFile(filepath.Join(expectDir, "kcl.mod.reverse.lock")) @@ -384,6 +385,10 @@ func TestVendorDeps(t *testing.T) { Sum: kcl2Sum, } + mppTest := orderedmap.NewOrderedMap[string, pkg.Dependency]() + mppTest.Set("kcl1", depKcl1) + mppTest.Set("kcl2", depKcl2) + kclPkg := pkg.KclPkg{ ModFile: pkg.ModFile{ HomePath: filepath.Join(testDir, "my_kcl"), @@ -392,20 +397,14 @@ func TestVendorDeps(t *testing.T) { // in the current package directory. VendorMode: false, Dependencies: pkg.Dependencies{ - Deps: map[string]pkg.Dependency{ - "kcl1": depKcl1, - "kcl2": depKcl2, - }, + Deps: mppTest, }, }, HomePath: filepath.Join(testDir, "my_kcl"), // The dependencies in the current kcl package are the dependencies of kcl.mod.lock, // not the dependencies in kcl.mod. Dependencies: pkg.Dependencies{ - Deps: map[string]pkg.Dependency{ - "kcl1": depKcl1, - "kcl2": depKcl2, - }, + Deps: mppTest, }, } @@ -468,6 +467,9 @@ func TestResolveDepsVendorMode(t *testing.T) { Sum: kcl2Sum, } + mppTest := orderedmap.NewOrderedMap[string, pkg.Dependency]() + mppTest.Set("kcl1", depKcl1) + mppTest.Set("kcl2", depKcl2) kclPkg := pkg.KclPkg{ ModFile: pkg.ModFile{ HomePath: home_path, @@ -476,20 +478,14 @@ func TestResolveDepsVendorMode(t *testing.T) { // in the current package directory. VendorMode: true, Dependencies: pkg.Dependencies{ - Deps: map[string]pkg.Dependency{ - "kcl1": depKcl1, - "kcl2": depKcl2, - }, + Deps: mppTest, }, }, HomePath: home_path, // The dependencies in the current kcl package are the dependencies of kcl.mod.lock, // not the dependencies in kcl.mod. Dependencies: pkg.Dependencies{ - Deps: map[string]pkg.Dependency{ - "kcl1": depKcl1, - "kcl2": depKcl2, - }, + Deps: mppTest, }, } mySearchPath := filepath.Join(home_path, "vendor") @@ -536,6 +532,10 @@ func TestCompileWithEntryFile(t *testing.T) { Sum: kcl2Sum, } + mppTest := orderedmap.NewOrderedMap[string, pkg.Dependency]() + mppTest.Set("kcl1", depKcl1) + mppTest.Set("kcl2", depKcl2) + kclPkg := pkg.KclPkg{ ModFile: pkg.ModFile{ HomePath: home_path, @@ -544,20 +544,14 @@ func TestCompileWithEntryFile(t *testing.T) { // in the current package directory. VendorMode: true, Dependencies: pkg.Dependencies{ - Deps: map[string]pkg.Dependency{ - "kcl1": depKcl1, - "kcl2": depKcl2, - }, + Deps: mppTest, }, }, HomePath: home_path, // The dependencies in the current kcl package are the dependencies of kcl.mod.lock, // not the dependencies in kcl.mod. Dependencies: pkg.Dependencies{ - Deps: map[string]pkg.Dependency{ - "kcl1": depKcl1, - "kcl2": depKcl2, - }, + Deps: mppTest, }, } @@ -631,15 +625,15 @@ func TestResolveMetadataInJsonStr(t *testing.T) { assert.Equal(t, err, nil) expectedDep := pkg.Dependencies{ - Deps: make(map[string]pkg.Dependency), + Deps: orderedmap.NewOrderedMap[string, pkg.Dependency](), } - expectedDep.Deps["flask_demo_kcl_manifests"] = pkg.Dependency{ + expectedDep.Deps.Set("flask_demo_kcl_manifests", pkg.Dependency{ Name: "flask_demo_kcl_manifests", FullName: "flask-demo-kcl-manifests_ade147b", Version: "ade147b", LocalFullPath: filepath.Join(globalPkgPath, "flask-demo-kcl-manifests_ade147b"), - } + }) expectedDepStr, err := json.Marshal(expectedDep) assert.Equal(t, err, nil) @@ -657,12 +651,12 @@ func TestResolveMetadataInJsonStr(t *testing.T) { assert.Equal(t, utils.DirExists(vendorDir), true) assert.Equal(t, utils.DirExists(filepath.Join(vendorDir, "flask-demo-kcl-manifests_ade147b")), true) - expectedDep.Deps["flask_demo_kcl_manifests"] = pkg.Dependency{ + expectedDep.Deps.Set("flask_demo_kcl_manifests", pkg.Dependency{ Name: "flask_demo_kcl_manifests", FullName: "flask-demo-kcl-manifests_ade147b", Version: "ade147b", LocalFullPath: filepath.Join(vendorDir, "flask-demo-kcl-manifests_ade147b"), - } + }) expectedDepStr, err = json.Marshal(expectedDep) assert.Equal(t, err, nil) @@ -1365,11 +1359,11 @@ func TestAddWithLocalPath(t *testing.T) { expectpkg, err := kpmcli.LoadPkgFromPath(expectpath) assert.Equal(t, err, nil) - assert.Equal(t, len(gotpkg.Dependencies.Deps), len(expectpkg.Dependencies.Deps)) - assert.Equal(t, gotpkg.Dependencies.Deps["dep_pkg"].FullName, expectpkg.Dependencies.Deps["dep_pkg"].FullName) - assert.Equal(t, gotpkg.Dependencies.Deps["dep_pkg"].Version, expectpkg.Dependencies.Deps["dep_pkg"].Version) - assert.Equal(t, gotpkg.Dependencies.Deps["dep_pkg"].LocalFullPath, filepath.Join(tmppath, "dep_pkg")) - assert.Equal(t, gotpkg.Dependencies.Deps["dep_pkg"].Source.Local.Path, "../dep_pkg") + assert.Equal(t, gotpkg.Dependencies.Deps.Len(), expectpkg.Dependencies.Deps.Len()) + assert.Equal(t, gotpkg.Dependencies.Deps.GetOrDefault("dep_pkg", pkg.TestPkgDependency).FullName, expectpkg.Dependencies.Deps.GetOrDefault("dep_pkg", pkg.TestPkgDependency).FullName) + assert.Equal(t, gotpkg.Dependencies.Deps.GetOrDefault("dep_pkg", pkg.TestPkgDependency).Version, expectpkg.Dependencies.Deps.GetOrDefault("dep_pkg", pkg.TestPkgDependency).Version) + assert.Equal(t, gotpkg.Dependencies.Deps.GetOrDefault("dep_pkg", pkg.TestPkgDependency).LocalFullPath, filepath.Join(tmppath, "dep_pkg")) + assert.Equal(t, gotpkg.Dependencies.Deps.GetOrDefault("dep_pkg", pkg.TestPkgDependency).Source.Local.Path, "../dep_pkg") } func TestRunOciWithSettingsFile(t *testing.T) { @@ -1431,12 +1425,12 @@ func TestLoadOciUrlDiffSetting(t *testing.T) { testPath := getTestDir("diffsettings") - pkg, err := kpmcli.LoadPkgFromPath(testPath) + pkg_local, err := kpmcli.LoadPkgFromPath(testPath) assert.Equal(t, err, nil) - assert.Equal(t, len(pkg.ModFile.Deps), 1) - assert.Equal(t, pkg.ModFile.Deps["oci_pkg"].Oci.Reg, "docker.io") - assert.Equal(t, pkg.ModFile.Deps["oci_pkg"].Oci.Repo, "test/oci_pkg") - assert.Equal(t, pkg.ModFile.Deps["oci_pkg"].Oci.Tag, "0.0.1") + assert.Equal(t, pkg_local.ModFile.Deps.Len(), 1) + assert.Equal(t, pkg_local.ModFile.Deps.GetOrDefault("oci_pkg", pkg.TestPkgDependency).Oci.Reg, "docker.io") + assert.Equal(t, pkg_local.ModFile.Deps.GetOrDefault("oci_pkg", pkg.TestPkgDependency).Oci.Repo, "test/oci_pkg") + assert.Equal(t, pkg_local.ModFile.Deps.GetOrDefault("oci_pkg", pkg.TestPkgDependency).Oci.Tag, "0.0.1") assert.Equal(t, err, nil) } diff --git a/pkg/cmd/cmd_update.go b/pkg/cmd/cmd_update.go index 32a2acc0..50168bfc 100644 --- a/pkg/cmd/cmd_update.go +++ b/pkg/cmd/cmd_update.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/dominikbraun/graph" + "github.com/elliotchance/orderedmap" "github.com/urfave/cli/v2" "golang.org/x/mod/module" "kcl-lang.io/kpm/pkg/client" @@ -107,13 +108,13 @@ func KpmUpdate(c *cli.Context, kpmcli *client.KpmClient) error { return reporter.NewErrorEvent(reporter.FailedUpdatingBuildList, err, "failed to update build list") } - // get all the vertices in the graph + // 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) + kclPkg.ModFile.Dependencies.Deps = orderedmap.NewOrderedMap[string, pkg.Dependency]() for _, module := range modules { err = InsertModuleToDeps(kclPkg, module, target, buildList, reqs) @@ -131,8 +132,8 @@ func KpmUpdate(c *cli.Context, kpmcli *client.KpmClient) error { // 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 { +// 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 { @@ -141,7 +142,7 @@ func GetModulesToUpdate(kclPkg *pkg.KclPkg, modulesToUpgrade []module.Version, var dep pkg.Dependency var ok bool - if dep, ok = kclPkg.Deps[pkgName]; !ok { + if dep, ok = kclPkg.Deps.Get(pkgName); !ok { return err } @@ -172,9 +173,9 @@ func GetModulesToUpdate(kclPkg *pkg.KclPkg, modulesToUpgrade []module.Version, return nil } -// InsertModuleToDeps checks whether module is present in the buildList and it is not the same as the target module, +// 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) { +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 } @@ -194,6 +195,6 @@ func InsertModuleToDeps(kclPkg *pkg.KclPkg, module module.Version, target module return reporter.NewErrorEvent(reporter.FailedGenerateSource, err, "failed to generate source") } } - kclPkg.ModFile.Dependencies.Deps[module.Path] = d + kclPkg.ModFile.Dependencies.Deps.Set(module.Path, d) return nil -} \ No newline at end of file +} diff --git a/pkg/mvs/mvs.go b/pkg/mvs/mvs.go index 52f414cf..78f57464 100644 --- a/pkg/mvs/mvs.go +++ b/pkg/mvs/mvs.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/dominikbraun/graph" + "github.com/elliotchance/orderedmap" "github.com/hashicorp/go-version" "golang.org/x/mod/module" "kcl-lang.io/kpm/pkg/3rdparty/mvs" @@ -83,13 +84,13 @@ func (r ReqsGraph) Upgrade(m module.Version) (module.Version, error) { return module.Version{}, err } } + mpp := orderedmap.NewOrderedMap[string, pkg.Dependency]() + mpp.Set(m.Path, d) deps := pkg.Dependencies{ - Deps: map[string]pkg.Dependency{ - m.Path: d, - }, + Deps: mpp, } lockDeps := pkg.Dependencies{ - Deps: make(map[string]pkg.Dependency), + Deps: orderedmap.NewOrderedMap[string, pkg.Dependency](), } _, err = r.KpmClient.DownloadDeps(&deps, &lockDeps, r.Graph, r.KpmPkg.HomePath, module.Version{}) if err != nil { @@ -147,13 +148,13 @@ func (r ReqsGraph) Previous(m module.Version) (module.Version, error) { return module.Version{}, err } } + mppDeps := orderedmap.NewOrderedMap[string, pkg.Dependency]() + mppDeps.Set(m.Path, d) deps := pkg.Dependencies{ - Deps: map[string]pkg.Dependency{ - m.Path: d, - }, + Deps: mppDeps, } lockDeps := pkg.Dependencies{ - Deps: make(map[string]pkg.Dependency), + Deps: orderedmap.NewOrderedMap[string, pkg.Dependency](), } _, err = r.KpmClient.DownloadDeps(&deps, &lockDeps, r.Graph, r.KpmPkg.HomePath, module.Version{}) if err != nil { diff --git a/pkg/package/modfile.go b/pkg/package/modfile.go index 79565139..c547c746 100644 --- a/pkg/package/modfile.go +++ b/pkg/package/modfile.go @@ -7,10 +7,10 @@ import ( "net/url" "os" "path/filepath" - "sort" "strings" "github.com/BurntSushi/toml" + orderedmap "github.com/elliotchance/orderedmap/v2" "kcl-lang.io/kcl-go/pkg/kcl" "oras.land/oras-go/v2/registry" @@ -124,12 +124,13 @@ func (profile *Profile) GetEntries() []string { // FillDependenciesInfo will fill registry information for all dependencies in a kcl.mod. func (modFile *ModFile) FillDependenciesInfo() error { - for k, v := range modFile.Deps { + for _, k := range modFile.Deps.Keys() { + v, _ := modFile.Deps.Get(k) err := v.FillDepInfo(modFile.HomePath) if err != nil { return err } - modFile.Deps[k] = v + modFile.Deps.Set(k, v) } return nil } @@ -144,32 +145,26 @@ func (modFile *ModFile) GetEntries() []string { // 'Dependencies' is dependencies section of 'kcl.mod'. type Dependencies struct { - Deps map[string]Dependency `json:"packages" toml:"dependencies,omitempty"` + Deps *orderedmap.OrderedMap[string, Dependency] `json:"packages" toml:"dependencies,omitempty"` } -// SortMapByKey will sort the dependencies by key. -func (deps *Dependencies) SortMapByKey() { - keys := make([]string, 0, len(deps.Deps)) - for k := range deps.Deps { - keys = append(keys, k) - } - sort.Strings(keys) - - sortedDeps := make(map[string]Dependency) - for _, k := range keys { - sortedDeps[k] = deps.Deps[k] - } - deps.Deps = sortedDeps -} // ToDepMetadata will transform the dependencies into metadata. // And check whether the dependency name conflicts. func (deps *Dependencies) ToDepMetadata() (*Dependencies, error) { depMetadata := Dependencies{ - Deps: make(map[string]Dependency), + Deps: orderedmap.NewOrderedMap[string, Dependency](), } - for _, d := range deps.Deps { - if _, ok := depMetadata.Deps[d.GetAliasName()]; ok { + for _, depName := range deps.Deps.Keys() { + d, ok := deps.Deps.Get(depName) + if !ok { + return nil, reporter.NewErrorEvent( + reporter.DependencyNotFoundInOrderedMap, + fmt.Errorf("dependency %d not found", depName), + "internal bugs, please contact us to fix it.", + ) + } + if _, ok := depMetadata.Deps.Get(d.GetAliasName()); ok { return nil, reporter.NewErrorEvent( reporter.PathIsEmpty, fmt.Errorf("dependency name conflict, '%s' already exists", d.GetAliasName()), @@ -178,14 +173,22 @@ func (deps *Dependencies) ToDepMetadata() (*Dependencies, error) { ) } d.Name = d.GetAliasName() - depMetadata.Deps[d.GetAliasName()] = d + ok = depMetadata.Deps.Set(d.GetAliasName(), d) + if !ok { + return nil, reporter.NewErrorEvent( + reporter.DependencyNotSetInOrderedMap, + fmt.Errorf("unable to set %d as dependency", depName), + "internal bugs, please contact us to fix it.", + ) + } } return &depMetadata, nil } func (deps *Dependencies) CheckForLocalDeps() bool { - for _, dep := range deps.Deps { + for _, depKeys := range deps.Deps.Keys() { + dep, _ := deps.Deps.Get(depKeys) if dep.IsFromLocal() { return true } @@ -435,7 +438,7 @@ func ModLockFileExists(path string) (bool, error) { // LoadLockDeps will load all dependencies from 'kcl.mod.lock'. func LoadLockDeps(homePath string) (*Dependencies, error) { deps := new(Dependencies) - deps.Deps = make(map[string]Dependency) + deps.Deps = orderedmap.NewOrderedMap[string, Dependency]() err := deps.loadLockFile(filepath.Join(homePath, MOD_LOCK_FILE)) if os.IsNotExist(err) { @@ -481,7 +484,7 @@ func NewModFile(opts *opt.InitOptions) *ModFile { Edition: defaultEdition, }, Dependencies: Dependencies{ - Deps: make(map[string]Dependency), + Deps: orderedmap.NewOrderedMap[string, Dependency](), }, } } @@ -514,7 +517,7 @@ func LoadModFile(homePath string) (*ModFile, error) { modFile.HomePath = homePath if modFile.Dependencies.Deps == nil { - modFile.Dependencies.Deps = make(map[string]Dependency) + modFile.Dependencies.Deps = orderedmap.NewOrderedMap[string, Dependency]() } err = modFile.FillDependenciesInfo() if err != nil { diff --git a/pkg/package/modfile_test.go b/pkg/package/modfile_test.go index ffe242f4..2194382d 100644 --- a/pkg/package/modfile_test.go +++ b/pkg/package/modfile_test.go @@ -22,7 +22,7 @@ func TestModFileWithDesc(t *testing.T) { assert.Equal(t, modFile.Pkg.Version, "0.0.1") assert.Equal(t, modFile.Pkg.Edition, "0.0.1") assert.Equal(t, modFile.Pkg.Description, "This is a test module with a description") - assert.Equal(t, len(modFile.Dependencies.Deps), 0) + assert.Equal(t, modFile.Dependencies.Deps.Len(), 0) assert.Equal(t, err, nil) } @@ -170,20 +170,20 @@ func TestLoadModFile(t *testing.T) { assert.Equal(t, modFile.Pkg.Version, "0.0.1") assert.Equal(t, modFile.Pkg.Edition, "0.0.1") - assert.Equal(t, len(modFile.Dependencies.Deps), 3) - assert.Equal(t, modFile.Dependencies.Deps["name"].Name, "name") - assert.Equal(t, modFile.Dependencies.Deps["name"].Source.Git.Url, "test_url") - assert.Equal(t, modFile.Dependencies.Deps["name"].Source.Git.Tag, "test_tag") - assert.Equal(t, modFile.Dependencies.Deps["name"].FullName, "name_test_tag") + assert.Equal(t, modFile.Dependencies.Deps.Len(), 3) + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("name", TestPkgDependency).Name, "name") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("name", TestPkgDependency).Source.Git.Url, "test_url") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("name", TestPkgDependency).Source.Git.Tag, "test_tag") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("name", TestPkgDependency).FullName, "name_test_tag") - assert.Equal(t, modFile.Dependencies.Deps["oci_name"].Name, "oci_name") - assert.Equal(t, modFile.Dependencies.Deps["oci_name"].Version, "oci_tag") - assert.Equal(t, modFile.Dependencies.Deps["oci_name"].Source.Oci.Tag, "oci_tag") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("oci_name", TestPkgDependency).Name, "oci_name") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("oci_name", TestPkgDependency).Version, "oci_tag") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("oci_name", TestPkgDependency).Source.Oci.Tag, "oci_tag") assert.Equal(t, err, nil) - assert.Equal(t, modFile.Dependencies.Deps["helloworld"].Name, "helloworld") - assert.Equal(t, modFile.Dependencies.Deps["helloworld"].Version, "0.1.2") - assert.Equal(t, modFile.Dependencies.Deps["helloworld"].Source.Oci.Tag, "0.1.2") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("helloworld", TestPkgDependency).Name, "helloworld") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("helloworld", TestPkgDependency).Version, "0.1.2") + assert.Equal(t, modFile.Dependencies.Deps.GetOrDefault("helloworld", TestPkgDependency).Source.Oci.Tag, "0.1.2") assert.Equal(t, err, nil) } @@ -191,21 +191,21 @@ func TestLoadLockDeps(t *testing.T) { testPath := getTestDir("load_lock_file") deps, err := LoadLockDeps(testPath) - assert.Equal(t, len(deps.Deps), 2) - assert.Equal(t, deps.Deps["name"].Name, "name") - assert.Equal(t, deps.Deps["name"].Version, "test_version") - assert.Equal(t, deps.Deps["name"].Sum, "test_sum") - assert.Equal(t, deps.Deps["name"].Source.Git.Url, "test_url") - assert.Equal(t, deps.Deps["name"].Source.Git.Tag, "test_tag") - assert.Equal(t, deps.Deps["name"].FullName, "test_version") - - assert.Equal(t, deps.Deps["oci_name"].Name, "oci_name") - assert.Equal(t, deps.Deps["oci_name"].Version, "test_version") - assert.Equal(t, deps.Deps["oci_name"].Sum, "test_sum") - assert.Equal(t, deps.Deps["oci_name"].Source.Oci.Reg, "test_reg") - assert.Equal(t, deps.Deps["oci_name"].Source.Oci.Repo, "test_repo") - assert.Equal(t, deps.Deps["oci_name"].Source.Oci.Tag, "test_oci_tag") - assert.Equal(t, deps.Deps["oci_name"].FullName, "test_version") + assert.Equal(t, deps.Deps.Len(), 2) + assert.Equal(t, deps.Deps.GetOrDefault("name", TestPkgDependency).Name, "name") + assert.Equal(t, deps.Deps.GetOrDefault("name", TestPkgDependency).Version, "test_version") + assert.Equal(t, deps.Deps.GetOrDefault("name", TestPkgDependency).Sum, "test_sum") + assert.Equal(t, deps.Deps.GetOrDefault("name", TestPkgDependency).Source.Git.Url, "test_url") + assert.Equal(t, deps.Deps.GetOrDefault("name", TestPkgDependency).Source.Git.Tag, "test_tag") + assert.Equal(t, deps.Deps.GetOrDefault("name", TestPkgDependency).FullName, "test_version") + + assert.Equal(t, deps.Deps.GetOrDefault("oci_name", TestPkgDependency).Name, "oci_name") + assert.Equal(t, deps.Deps.GetOrDefault("oci_name", TestPkgDependency).Version, "test_version") + assert.Equal(t, deps.Deps.GetOrDefault("oci_name", TestPkgDependency).Sum, "test_sum") + assert.Equal(t, deps.Deps.GetOrDefault("oci_name", TestPkgDependency).Source.Oci.Reg, "test_reg") + assert.Equal(t, deps.Deps.GetOrDefault("oci_name", TestPkgDependency).Source.Oci.Repo, "test_repo") + assert.Equal(t, deps.Deps.GetOrDefault("oci_name", TestPkgDependency).Source.Oci.Tag, "test_oci_tag") + assert.Equal(t, deps.Deps.GetOrDefault("oci_name", TestPkgDependency).FullName, "test_version") assert.Equal(t, err, nil) } diff --git a/pkg/package/package.go b/pkg/package/package.go index c2cbc743..dc856ceb 100644 --- a/pkg/package/package.go +++ b/pkg/package/package.go @@ -6,6 +6,7 @@ import ( "path/filepath" "strings" + orderedmap "github.com/elliotchance/orderedmap/v2" "kcl-lang.io/kcl-go/pkg/kcl" "kcl-lang.io/kpm/pkg/constants" errors "kcl-lang.io/kpm/pkg/errors" @@ -14,6 +15,13 @@ import ( "kcl-lang.io/kpm/pkg/utils" ) +var TestPkgDependency = Dependency{ + Name: "kcl", + FullName: "kcl", + Version: "0.0.0", + Sum: "Sum", +} + type KclPkg struct { ModFile ModFile HomePath string @@ -32,7 +40,7 @@ func NewKclPkg(opts *opt.InitOptions) KclPkg { return KclPkg{ ModFile: *NewModFile(opts), HomePath: opts.InitPath, - Dependencies: Dependencies{Deps: make(map[string]Dependency)}, + Dependencies: Dependencies{Deps: orderedmap.NewOrderedMap[string, Dependency]()}, } } @@ -50,9 +58,10 @@ func LoadKclPkg(pkgPath string) (*KclPkg, error) { } // Align the dependencies between kcl.mod and kcl.mod.lock. - for name, dep := range modFile.Dependencies.Deps { + for _, name := range modFile.Dependencies.Deps.Keys() { + dep, _ := modFile.Dependencies.Deps.Get(name) if dep.Local != nil { - if ldep, ok := deps.Deps[name]; ok { + if ldep, ok := deps.Deps.Get(name); ok { abs, err := filepath.Abs(filepath.Join(pkgPath, dep.Local.Path)) if err != nil { return nil, reporter.NewErrorEvent(reporter.Bug, err, "internal bugs, please contact us to fix it.") @@ -60,8 +69,8 @@ func LoadKclPkg(pkgPath string) (*KclPkg, error) { ldep.LocalFullPath = abs dep.LocalFullPath = abs ldep.Source = dep.Source - deps.Deps[name] = ldep - modFile.Dependencies.Deps[name] = dep + deps.Deps.Set(name, ldep) + modFile.Dependencies.Deps.Set(name, dep) } } } @@ -175,7 +184,6 @@ func (kclPkg *KclPkg) LocalVendorPath() string { // updateModAndLockFile will update kcl.mod and kcl.mod.lock func (kclPkg *KclPkg) UpdateModAndLockFile() error { // Generate file kcl.mod. - kclPkg.ModFile.Dependencies.SortMapByKey() err := kclPkg.ModFile.StoreModFile() if err != nil { return err diff --git a/pkg/package/package_test.go b/pkg/package/package_test.go index c68bbe57..6437a55b 100644 --- a/pkg/package/package_test.go +++ b/pkg/package/package_test.go @@ -49,8 +49,8 @@ func TestLoadKclPkg(t *testing.T) { assert.Equal(t, kclPkg.ModFile.Pkg.Name, "test_name") assert.Equal(t, kclPkg.ModFile.Pkg.Version, "0.0.1") assert.Equal(t, kclPkg.ModFile.Pkg.Edition, runner.GetKclVersion()) - assert.Equal(t, len(kclPkg.ModFile.Dependencies.Deps), 0) - assert.Equal(t, len(kclPkg.Dependencies.Deps), 0) + assert.Equal(t, kclPkg.ModFile.Dependencies.Deps.Len(), 0) + assert.Equal(t, kclPkg.Dependencies.Deps.Len(), 0) } func TestCheck(t *testing.T) { @@ -104,29 +104,29 @@ func TestLoadKclPkgFromTar(t *testing.T) { assert.Equal(t, kclPkg.ModFile.Pkg.Edition, "0.0.1") assert.Equal(t, kclPkg.ModFile.Pkg.Version, "0.0.3") - assert.Equal(t, len(kclPkg.ModFile.Deps), 2) - assert.Equal(t, kclPkg.ModFile.Deps["konfig"].Name, "konfig") - assert.Equal(t, kclPkg.ModFile.Deps["konfig"].FullName, "konfig_v0.0.1") - assert.Equal(t, kclPkg.ModFile.Deps["konfig"].Git.Url, "https://github.com/awesome-kusion/konfig.git") - assert.Equal(t, kclPkg.ModFile.Deps["konfig"].Git.Tag, "v0.0.1") - - assert.Equal(t, kclPkg.ModFile.Deps["oci_konfig"].Name, "oci_konfig") - assert.Equal(t, kclPkg.ModFile.Deps["oci_konfig"].FullName, "oci_konfig_0.0.1") - assert.Equal(t, kclPkg.ModFile.Deps["oci_konfig"].Oci.Tag, "0.0.1") - - assert.Equal(t, len(kclPkg.Deps), 2) - assert.Equal(t, kclPkg.Deps["konfig"].Name, "konfig") - assert.Equal(t, kclPkg.Deps["konfig"].FullName, "konfig_v0.0.1") - assert.Equal(t, kclPkg.Deps["konfig"].Git.Url, "https://github.com/awesome-kusion/konfig.git") - assert.Equal(t, kclPkg.Deps["konfig"].Git.Tag, "v0.0.1") - assert.Equal(t, kclPkg.Deps["konfig"].Sum, "XFvHdBAoY/+qpJWmj8cjwOwZO8a3nX/7SE35cTxQOFU=") - - assert.Equal(t, kclPkg.Deps["oci_konfig"].Name, "oci_konfig") - assert.Equal(t, kclPkg.Deps["oci_konfig"].FullName, "oci_konfig_0.0.1") - assert.Equal(t, kclPkg.Deps["oci_konfig"].Oci.Reg, "ghcr.io") - assert.Equal(t, kclPkg.Deps["oci_konfig"].Oci.Repo, "awesome-kusion/oci_konfig") - assert.Equal(t, kclPkg.Deps["oci_konfig"].Oci.Tag, "0.0.1") - assert.Equal(t, kclPkg.Deps["oci_konfig"].Sum, "sLr3e6W4RPrXYyswdOSiKqkHes1QHX2tk6SwxAPDqqo=") + assert.Equal(t, kclPkg.ModFile.Deps.Len(), 2) + assert.Equal(t, kclPkg.ModFile.Deps.GetOrDefault("konfig", TestPkgDependency).Name, "konfig") + assert.Equal(t, kclPkg.ModFile.Deps.GetOrDefault("konfig", TestPkgDependency).FullName, "konfig_v0.0.1") + assert.Equal(t, kclPkg.ModFile.Deps.GetOrDefault("konfig", TestPkgDependency).Git.Url, "https://github.com/awesome-kusion/konfig.git") + assert.Equal(t, kclPkg.ModFile.Deps.GetOrDefault("konfig", TestPkgDependency).Git.Tag, "v0.0.1") + + assert.Equal(t, kclPkg.ModFile.Deps.GetOrDefault("oci_konfig", TestPkgDependency).Name, "oci_konfig") + assert.Equal(t, kclPkg.ModFile.Deps.GetOrDefault("oci_konfig", TestPkgDependency).FullName, "oci_konfig_0.0.1") + assert.Equal(t, kclPkg.ModFile.Deps.GetOrDefault("oci_konfig", TestPkgDependency).Oci.Tag, "0.0.1") + + assert.Equal(t, kclPkg.Deps.Len(), 2) + assert.Equal(t, kclPkg.Deps.GetOrDefault("konfig", TestPkgDependency).Name, "konfig") + assert.Equal(t, kclPkg.Deps.GetOrDefault("konfig", TestPkgDependency).FullName, "konfig_v0.0.1") + assert.Equal(t, kclPkg.Deps.GetOrDefault("konfig", TestPkgDependency).Git.Url, "https://github.com/awesome-kusion/konfig.git") + assert.Equal(t, kclPkg.Deps.GetOrDefault("konfig", TestPkgDependency).Git.Tag, "v0.0.1") + assert.Equal(t, kclPkg.Deps.GetOrDefault("konfig", TestPkgDependency).Sum, "XFvHdBAoY/+qpJWmj8cjwOwZO8a3nX/7SE35cTxQOFU=") + + assert.Equal(t, kclPkg.Deps.GetOrDefault("oci_konfig", TestPkgDependency).Name, "oci_konfig") + assert.Equal(t, kclPkg.Deps.GetOrDefault("oci_konfig", TestPkgDependency).FullName, "oci_konfig_0.0.1") + assert.Equal(t, kclPkg.Deps.GetOrDefault("oci_konfig", TestPkgDependency).Oci.Reg, "ghcr.io") + assert.Equal(t, kclPkg.Deps.GetOrDefault("oci_konfig", TestPkgDependency).Oci.Repo, "awesome-kusion/oci_konfig") + assert.Equal(t, kclPkg.Deps.GetOrDefault("oci_konfig", TestPkgDependency).Oci.Tag, "0.0.1") + assert.Equal(t, kclPkg.Deps.GetOrDefault("oci_konfig", TestPkgDependency).Sum, "sLr3e6W4RPrXYyswdOSiKqkHes1QHX2tk6SwxAPDqqo=") assert.Equal(t, kclPkg.GetPkgTag(), "0.0.3") assert.Equal(t, kclPkg.GetPkgName(), "kcl1") diff --git a/pkg/package/toml.go b/pkg/package/toml.go index c21ef54b..57db0123 100644 --- a/pkg/package/toml.go +++ b/pkg/package/toml.go @@ -26,6 +26,7 @@ import ( "strings" "github.com/BurntSushi/toml" + orderedmap "github.com/elliotchance/orderedmap/v2" "kcl-lang.io/kpm/pkg/constants" "kcl-lang.io/kpm/pkg/reporter" @@ -61,9 +62,10 @@ const DEPS_PATTERN = "[dependencies]" func (dep *Dependencies) MarshalTOML() string { var sb strings.Builder - if len(dep.Deps) != 0 { + if dep.Deps.Len() != 0 { sb.WriteString(DEPS_PATTERN) - for _, dep := range dep.Deps { + for _, depKeys := range dep.Deps.Keys() { + dep, _ := dep.Deps.Get(depKeys) sb.WriteString(NEWLINE) sb.WriteString(dep.MarshalTOML()) } @@ -207,7 +209,7 @@ func (mod *ModFile) UnmarshalTOML(data interface{}) error { if v, ok := meta[DEPS_FLAG]; ok { deps := Dependencies{ - Deps: make(map[string]Dependency), + Deps: orderedmap.NewOrderedMap[string, Dependency](), } err := deps.UnmarshalModTOML(v) if err != nil { @@ -294,7 +296,7 @@ func (deps *Dependencies) UnmarshalModTOML(data interface{}) error { if err != nil { return err } - deps.Deps[k] = dep + deps.Deps.Set(k, dep) } return nil diff --git a/pkg/package/toml_test.go b/pkg/package/toml_test.go index d6d4bc6c..1df58d90 100644 --- a/pkg/package/toml_test.go +++ b/pkg/package/toml_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/BurntSushi/toml" + orderedmap "github.com/elliotchance/orderedmap/v2" "github.com/stretchr/testify/assert" - "kcl-lang.io/kpm/pkg/utils" ) @@ -24,7 +24,7 @@ func TestMarshalTOML(t *testing.T) { Exclude: []string{"target/", ".git/", "*.log"}, }, Dependencies: Dependencies{ - make(map[string]Dependency), + orderedmap.NewOrderedMap[string, Dependency](), }, } @@ -50,8 +50,8 @@ func TestMarshalTOML(t *testing.T) { }, } - modfile.Dependencies.Deps["MyOciKcl1_0.0.1"] = ociDep - modfile.Dependencies.Deps["MyKcl1_v0.0.2"] = dep + modfile.Dependencies.Deps.Set("MyOciKcl1_0.0.1", ociDep) + modfile.Dependencies.Deps.Set("MyKcl1_v0.0.2", dep) got_data := modfile.MarshalTOML() @@ -81,19 +81,19 @@ func TestUnMarshalTOML(t *testing.T) { assert.Equal(t, modfile.Pkg.Version, "v0.0.1") assert.Equal(t, modfile.Pkg.Include, []string{"src/", "README.md", "LICENSE"}) assert.Equal(t, modfile.Pkg.Exclude, []string{"target/", ".git/", "*.log"}) - assert.Equal(t, len(modfile.Dependencies.Deps), 2) - assert.NotEqual(t, modfile.Dependencies.Deps["MyKcl1"], nil) - assert.Equal(t, modfile.Dependencies.Deps["MyKcl1"].Name, "MyKcl1") - assert.Equal(t, modfile.Dependencies.Deps["MyKcl1"].FullName, "MyKcl1_v0.0.2") - assert.NotEqual(t, modfile.Dependencies.Deps["MyKcl1"].Source.Git, nil) - assert.Equal(t, modfile.Dependencies.Deps["MyKcl1"].Source.Git.Url, "https://github.com/test/MyKcl1.git") - assert.Equal(t, modfile.Dependencies.Deps["MyKcl1"].Source.Git.Tag, "v0.0.2") - - assert.NotEqual(t, modfile.Dependencies.Deps["MyOciKcl1"], nil) - assert.Equal(t, modfile.Dependencies.Deps["MyOciKcl1"].Name, "MyOciKcl1") - assert.Equal(t, modfile.Dependencies.Deps["MyOciKcl1"].FullName, "MyOciKcl1_0.0.1") - assert.NotEqual(t, modfile.Dependencies.Deps["MyOciKcl1"].Source.Oci, nil) - assert.Equal(t, modfile.Dependencies.Deps["MyOciKcl1"].Source.Oci.Tag, "0.0.1") + assert.Equal(t, modfile.Dependencies.Deps.Len(), 2) + assert.NotEqual(t, modfile.Dependencies.Deps.GetOrDefault("MyKcl1", TestPkgDependency), nil) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Name, "MyKcl1") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("MyKcl1", TestPkgDependency).FullName, "MyKcl1_v0.0.2") + assert.NotEqual(t, modfile.Dependencies.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Source.Git, nil) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Source.Git.Url, "https://github.com/test/MyKcl1.git") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Source.Git.Tag, "v0.0.2") + + assert.NotEqual(t, modfile.Dependencies.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency), nil) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Name, "MyOciKcl1") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).FullName, "MyOciKcl1_0.0.1") + assert.NotEqual(t, modfile.Dependencies.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Source.Oci, nil) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Source.Oci.Tag, "0.0.1") } func TestMarshalLockToml(t *testing.T) { @@ -125,11 +125,11 @@ func TestMarshalLockToml(t *testing.T) { } deps := Dependencies{ - make(map[string]Dependency), + orderedmap.NewOrderedMap[string, Dependency](), } - deps.Deps[dep.Name] = dep - deps.Deps[ociDep.Name] = ociDep + deps.Deps.Set(dep.Name, dep) + deps.Deps.Set(ociDep.Name, ociDep) tomlStr, _ := deps.MarshalLockTOML() expected_data, _ := os.ReadFile(filepath.Join(getTestDir(testTomlDir), "expected_lock.toml")) expected_toml := string(expected_data) @@ -138,32 +138,32 @@ func TestMarshalLockToml(t *testing.T) { func TestUnmarshalLockToml(t *testing.T) { deps := Dependencies{ - make(map[string]Dependency), + orderedmap.NewOrderedMap[string, Dependency](), } expected_data, _ := os.ReadFile(filepath.Join(getTestDir(testTomlDir), "expected_lock.toml")) expected_toml := string(expected_data) _ = deps.UnmarshalLockTOML(expected_toml) - assert.Equal(t, len(deps.Deps), 2) - assert.NotEqual(t, deps.Deps["MyKcl1"], nil) - assert.Equal(t, deps.Deps["MyKcl1"].Name, "MyKcl1") - assert.Equal(t, deps.Deps["MyKcl1"].FullName, "MyKcl1_v0.0.2") - assert.Equal(t, deps.Deps["MyKcl1"].Version, "v0.0.2") - assert.Equal(t, deps.Deps["MyKcl1"].Sum, "hjkasdahjksdasdhjk") - assert.NotEqual(t, deps.Deps["MyKcl1"].Source.Git, nil) - assert.Equal(t, deps.Deps["MyKcl1"].Source.Git.Url, "https://github.com/test/MyKcl1.git") - assert.Equal(t, deps.Deps["MyKcl1"].Source.Git.Tag, "v0.0.2") - - assert.NotEqual(t, deps.Deps["MyOciKcl1"], nil) - assert.Equal(t, deps.Deps["MyOciKcl1"].Name, "MyOciKcl1") - assert.Equal(t, deps.Deps["MyOciKcl1"].FullName, "MyOciKcl1_0.0.1") - assert.Equal(t, deps.Deps["MyOciKcl1"].Version, "0.0.1") - assert.Equal(t, deps.Deps["MyOciKcl1"].Sum, "hjkasdahjksdasdhjk") - assert.NotEqual(t, deps.Deps["MyOciKcl1"].Source.Oci, nil) - assert.Equal(t, deps.Deps["MyOciKcl1"].Source.Oci.Reg, "test_reg") - assert.Equal(t, deps.Deps["MyOciKcl1"].Source.Oci.Repo, "test_repo") - assert.Equal(t, deps.Deps["MyOciKcl1"].Source.Oci.Tag, "0.0.1") + assert.Equal(t, deps.Deps.Len(), 2) + assert.NotEqual(t, deps.Deps.GetOrDefault("MyKcl1", TestPkgDependency), nil) + assert.Equal(t, deps.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Name, "MyKcl1") + assert.Equal(t, deps.Deps.GetOrDefault("MyKcl1", TestPkgDependency).FullName, "MyKcl1_v0.0.2") + assert.Equal(t, deps.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Version, "v0.0.2") + assert.Equal(t, deps.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Sum, "hjkasdahjksdasdhjk") + assert.NotEqual(t, deps.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Source.Git, nil) + assert.Equal(t, deps.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Source.Git.Url, "https://github.com/test/MyKcl1.git") + assert.Equal(t, deps.Deps.GetOrDefault("MyKcl1", TestPkgDependency).Source.Git.Tag, "v0.0.2") + + assert.NotEqual(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency), nil) + assert.Equal(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Name, "MyOciKcl1") + assert.Equal(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).FullName, "MyOciKcl1_0.0.1") + assert.Equal(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Version, "0.0.1") + assert.Equal(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Sum, "hjkasdahjksdasdhjk") + assert.NotEqual(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Source.Oci, nil) + assert.Equal(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Source.Oci.Reg, "test_reg") + assert.Equal(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Source.Oci.Repo, "test_repo") + assert.Equal(t, deps.Deps.GetOrDefault("MyOciKcl1", TestPkgDependency).Source.Oci.Tag, "0.0.1") } func TestUnMarshalTOMLWithProfile(t *testing.T) { @@ -194,13 +194,13 @@ func TestUnMarshalOciUrl(t *testing.T) { for _, tc := range testCases { modfile, err := LoadModFile(filepath.Join(testDataDir, tc.Name)) assert.Equal(t, err, nil) - assert.Equal(t, len(modfile.Dependencies.Deps), 1) - assert.Equal(t, modfile.Dependencies.Deps["oci_pkg_name"].Name, tc.DepName) - assert.Equal(t, modfile.Dependencies.Deps["oci_pkg_name"].FullName, tc.DepFullName) - assert.Equal(t, modfile.Dependencies.Deps["oci_pkg_name"].Version, tc.DepVersion) - assert.Equal(t, modfile.Dependencies.Deps["oci_pkg_name"].Source.Oci.Reg, tc.DepSourceReg) - assert.Equal(t, modfile.Dependencies.Deps["oci_pkg_name"].Source.Oci.Repo, tc.DepSourceRepo) - assert.Equal(t, modfile.Dependencies.Deps["oci_pkg_name"].Source.Oci.Tag, tc.DepVersion) + assert.Equal(t, modfile.Dependencies.Deps.Len(), 1) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("oci_pkg_name", TestPkgDependency).Name, tc.DepName) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("oci_pkg_name", TestPkgDependency).FullName, tc.DepFullName) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("oci_pkg_name", TestPkgDependency).Version, tc.DepVersion) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("oci_pkg_name", TestPkgDependency).Source.Oci.Reg, tc.DepSourceReg) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("oci_pkg_name", TestPkgDependency).Source.Oci.Repo, tc.DepSourceRepo) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("oci_pkg_name", TestPkgDependency).Source.Oci.Tag, tc.DepVersion) } } @@ -231,7 +231,7 @@ func TestMarshalOciUrl(t *testing.T) { Version: "0.0.1", }, Dependencies: Dependencies{ - make(map[string]Dependency), + orderedmap.NewOrderedMap[string, Dependency](), }, } @@ -246,7 +246,7 @@ func TestMarshalOciUrl(t *testing.T) { }, } - modfile.Dependencies.Deps["oci_pkg_0.0.1"] = ociDep + modfile.Dependencies.Deps.Set("oci_pkg_0.0.1", ociDep) got_data := modfile.MarshalTOML() _, err = gotFile.WriteString(got_data) @@ -258,13 +258,13 @@ func TestMarshalOciUrl(t *testing.T) { assert.Equal(t, expect.Pkg.Name, got.Pkg.Name) assert.Equal(t, expect.Pkg.Edition, got.Pkg.Edition) assert.Equal(t, expect.Pkg.Version, got.Pkg.Version) - assert.Equal(t, len(expect.Dependencies.Deps), len(got.Dependencies.Deps)) - assert.Equal(t, expect.Dependencies.Deps["oci_pkg"].Name, got.Dependencies.Deps["oci_pkg"].Name) - assert.Equal(t, expect.Dependencies.Deps["oci_pkg"].FullName, got.Dependencies.Deps["oci_pkg"].FullName) - assert.Equal(t, expect.Dependencies.Deps["oci_pkg"].Source.Oci.Reg, got.Dependencies.Deps["oci_pkg"].Source.Oci.Reg) - assert.Equal(t, expect.Dependencies.Deps["oci_pkg"].Source.Oci.Repo, got.Dependencies.Deps["oci_pkg"].Source.Oci.Repo) - assert.Equal(t, expect.Dependencies.Deps["oci_pkg"].Source.Oci.Tag, got.Dependencies.Deps["oci_pkg"].Source.Oci.Tag) - assert.Equal(t, expect.Dependencies.Deps["oci_pkg"].Source.IntoOciUrl(), got.Dependencies.Deps["oci_pkg"].Source.IntoOciUrl()) + assert.Equal(t, expect.Dependencies.Deps.Len(), got.Dependencies.Deps.Len()) + assert.Equal(t, expect.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Name, got.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Name) + assert.Equal(t, expect.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).FullName, got.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).FullName) + assert.Equal(t, expect.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Source.Oci.Reg, got.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Source.Oci.Reg) + assert.Equal(t, expect.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Source.Oci.Repo, got.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Source.Oci.Repo) + assert.Equal(t, expect.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Source.Oci.Tag, got.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Source.Oci.Tag) + assert.Equal(t, expect.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Source.IntoOciUrl(), got.Dependencies.Deps.GetOrDefault("oci_pkg", TestPkgDependency).Source.IntoOciUrl()) } func TestMarshalOciUrlIntoFile(t *testing.T) { diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index 8fc3cd6e..247f7b78 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -105,6 +105,8 @@ const ( DownloadingFromGit LocalPathNotExist PathIsEmpty + DependencyNotFoundInOrderedMap + DependencyNotSetInOrderedMap ConflictPkgName AddItselfAsDep PkgTagExists diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 77cd615a..64c63609 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -16,7 +16,7 @@ import ( "regexp" "strings" - "github.com/docker/distribution/reference" + "github.com/distribution/reference" "github.com/moby/term" "kcl-lang.io/kpm/pkg/constants"