diff --git a/pkg/client/add.go b/pkg/client/add.go index 05ad039e..3ba65af9 100644 --- a/pkg/client/add.go +++ b/pkg/client/add.go @@ -19,6 +19,19 @@ type AddOptions struct { type AddOption func(*AddOptions) error +func WithAlias(alias string) AddOption { + return func(opts *AddOptions) error { + if opts.Source == nil { + return fmt.Errorf("source cannot be nil") + } + if opts.Source.ModSpec.IsNil() { + return fmt.Errorf("modSpec cannot be nil") + } + opts.Source.ModSpec.Alias = alias + return nil + } +} + func WithAddModSpec(modSpec *downloader.ModSpec) AddOption { return func(opts *AddOptions) error { if modSpec == nil { @@ -146,8 +159,15 @@ func (c *KpmClient) Add(options ...AddOption) error { depSource.ModSpec = modSpec } + var depName string + if opts.Source.ModSpec.Alias != "" { + depName = opts.Source.ModSpec.Alias + } else { + depName = depPkg.ModFile.Pkg.Name + } + dep := pkg.Dependency{ - Name: depPkg.ModFile.Pkg.Name, + Name: depName, FullName: depPkg.GetPkgFullName(), Version: depPkg.ModFile.Pkg.Version, LocalFullPath: depPkg.HomePath, diff --git a/pkg/client/add_test.go b/pkg/client/add_test.go index b5f5b00b..a04d9998 100644 --- a/pkg/client/add_test.go +++ b/pkg/client/add_test.go @@ -7,6 +7,7 @@ import ( "github.com/otiai10/copy" "github.com/stretchr/testify/assert" + "kcl-lang.io/kpm/pkg/downloader" pkg "kcl-lang.io/kpm/pkg/package" "kcl-lang.io/kpm/pkg/utils" ) @@ -135,3 +136,87 @@ func testAddWithModSpec(t *testing.T) { }) } } + +func TestAddRenameWithModSpec(t *testing.T) { + testDir := getTestDir("add_with_mod_spec") + pkgPath := filepath.Join(testDir, "rename") + + modbkPath := filepath.Join(pkgPath, "kcl.mod.bk") + modPath := filepath.Join(pkgPath, "kcl.mod") + modExpect := filepath.Join(pkgPath, "kcl.mod.expect") + lockbkPath := filepath.Join(pkgPath, "kcl.mod.lock.bk") + lockPath := filepath.Join(pkgPath, "kcl.mod.lock") + lockExpect := filepath.Join(pkgPath, "kcl.mod.lock.expect") + + err := copy.Copy(modbkPath, modPath) + if err != nil { + t.Fatal(err) + } + + err = copy.Copy(lockbkPath, lockPath) + if err != nil { + t.Fatal(err) + } + + defer func() { + // remove the copied files + err := os.RemoveAll(modPath) + if err != nil { + t.Fatal(err) + } + err = os.RemoveAll(lockPath) + if err != nil { + t.Fatal(err) + } + }() + + kpmcli, err := NewKpmClient() + if err != nil { + t.Fatal(err) + } + + kpkg, err := pkg.LoadKclPkgWithOpts( + pkg.WithPath(pkgPath), + pkg.WithSettings(kpmcli.GetSettings()), + ) + + if err != nil { + t.Fatal(err) + } + + err = kpmcli.Add( + WithAddKclPkg(kpkg), + WithAddSourceUrl("oci://ghcr.io/kcl-lang/helloworld?tag=0.1.4"), + WithAddModSpec(&downloader.ModSpec{ + Name: "subhelloworld", + Version: "0.0.1", + }), + WithAlias("newpkg"), + ) + + if err != nil { + t.Fatal(err) + } + + expectedMod, err := os.ReadFile(modExpect) + if err != nil { + t.Fatal(err) + } + gotMod, err := os.ReadFile(modPath) + if err != nil { + t.Fatal(err) + } + + expectedLock, err := os.ReadFile(lockExpect) + if err != nil { + t.Fatal(err) + } + + gotLock, err := os.ReadFile(lockPath) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, utils.RmNewline(string(expectedMod)), utils.RmNewline(string(gotMod))) + assert.Equal(t, utils.RmNewline(string(expectedLock)), utils.RmNewline(string(gotLock))) +} diff --git a/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.bk b/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.bk new file mode 100644 index 00000000..abbf2dda --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.bk @@ -0,0 +1,4 @@ +[package] +name = "rename" +edition = "v0.10.0" +version = "0.0.1" diff --git a/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.expect b/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.expect new file mode 100644 index 00000000..32c28baa --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.expect @@ -0,0 +1,7 @@ +[package] +name = "rename" +edition = "v0.10.0" +version = "0.0.1" + +[dependencies] +newpkg = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.4", package = "subhelloworld", version = "0.0.1" } diff --git a/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.lock.bk b/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.lock.bk new file mode 100644 index 00000000..e69de29b diff --git a/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.lock.expect b/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.lock.expect new file mode 100644 index 00000000..8be56776 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/rename/kcl.mod.lock.expect @@ -0,0 +1,8 @@ +[dependencies] + [dependencies.newpkg] + name = "newpkg" + full_name = "subhelloworld_0.0.1" + version = "0.0.1" + reg = "ghcr.io" + repo = "kcl-lang/helloworld" + oci_tag = "0.1.4" diff --git a/pkg/client/test_data/add_with_mod_spec/rename/main.k b/pkg/client/test_data/add_with_mod_spec/rename/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/client/test_data/add_with_mod_spec/rename/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/pkg/downloader/source.go b/pkg/downloader/source.go index d32abb35..d3a33fed 100644 --- a/pkg/downloader/source.go +++ b/pkg/downloader/source.go @@ -20,6 +20,7 @@ import ( type ModSpec struct { Name string Version string + Alias string } // IsNil returns true if the ModSpec is nil. diff --git a/pkg/downloader/toml.go b/pkg/downloader/toml.go index c2201382..e42ec578 100644 --- a/pkg/downloader/toml.go +++ b/pkg/downloader/toml.go @@ -16,7 +16,11 @@ const SPEC_PATTERN = "%s = %q" func (ps *ModSpec) MarshalTOML() string { var sb strings.Builder if ps != nil && len(ps.Version) != 0 && len(ps.Name) != 0 { - sb.WriteString(fmt.Sprintf(SPEC_PATTERN, ps.Name, ps.Version)) + if len(ps.Alias) == 0 { + sb.WriteString(fmt.Sprintf("%q", ps.Version)) + } else { + sb.WriteString(fmt.Sprintf(SOURCE_PATTERN, fmt.Sprintf("package = %q, version = %q", ps.Name, ps.Version))) + } return sb.String() } @@ -28,16 +32,21 @@ func (source *Source) MarshalTOML() string { if source.SpecOnly() { return source.ModSpec.MarshalTOML() } else { - var pkgVersion string + var pkgSpec string var tomlStr string + if source.ModSpec != nil && len(source.ModSpec.Version) > 0 { - pkgVersion = fmt.Sprintf(", version = %q", source.ModSpec.Version) + if source.ModSpec.Alias != "" { + pkgSpec = fmt.Sprintf(", package = %q, version = %q", source.ModSpec.Name, source.ModSpec.Version) + } else { + pkgSpec = fmt.Sprintf(", version = %q", source.ModSpec.Version) + } } if source.Git != nil { tomlStr = source.Git.MarshalTOML() if len(tomlStr) != 0 { - tomlStr = fmt.Sprintf(SOURCE_PATTERN, tomlStr+pkgVersion) + tomlStr = fmt.Sprintf(SOURCE_PATTERN, tomlStr+pkgSpec) } } @@ -45,7 +54,7 @@ func (source *Source) MarshalTOML() string { tomlStr = source.Oci.MarshalTOML() if len(tomlStr) != 0 { if len(source.Oci.Reg) != 0 && len(source.Oci.Repo) != 0 { - tomlStr = fmt.Sprintf(SOURCE_PATTERN, tomlStr+pkgVersion) + tomlStr = fmt.Sprintf(SOURCE_PATTERN, tomlStr+pkgSpec) } } } @@ -53,15 +62,11 @@ func (source *Source) MarshalTOML() string { if source.Local != nil { tomlStr = source.Local.MarshalTOML() if len(tomlStr) != 0 { - tomlStr = fmt.Sprintf(SOURCE_PATTERN, tomlStr+pkgVersion) + tomlStr = fmt.Sprintf(SOURCE_PATTERN, tomlStr+pkgSpec) } } - if source.ModSpec != nil && len(source.ModSpec.Name) != 0 { - sb.WriteString(fmt.Sprintf(DEP_PATTERN, source.ModSpec.Name, tomlStr)) - } else { - sb.WriteString(tomlStr) - } + sb.WriteString(tomlStr) } return sb.String() @@ -160,14 +165,19 @@ func (source *Source) UnmarshalModTOML(data interface{}) error { source.Oci = &oci } + pSpec := ModSpec{} if v, ok := meta["version"].(string); ok { - pSpec := ModSpec{} err := pSpec.UnmarshalModTOML(v) if err != nil { return err } source.ModSpec = &pSpec } + + if v, ok := meta["package"].(string); ok { + pSpec.Name = v + source.ModSpec = &pSpec + } } _, ok = data.(string) diff --git a/pkg/package/test_data/test_rename_pkg/kcl.mod b/pkg/package/test_data/test_rename_pkg/kcl.mod new file mode 100644 index 00000000..32c28baa --- /dev/null +++ b/pkg/package/test_data/test_rename_pkg/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "rename" +edition = "v0.10.0" +version = "0.0.1" + +[dependencies] +newpkg = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.4", package = "subhelloworld", version = "0.0.1" } diff --git a/pkg/package/toml.go b/pkg/package/toml.go index f58bcf89..687c9733 100644 --- a/pkg/package/toml.go +++ b/pkg/package/toml.go @@ -89,12 +89,14 @@ const DEP_PATTERN = "%s = %s" func (dep *Dependency) MarshalTOML() string { var sb strings.Builder - if dep.Source.ModSpec != nil && dep.Source.ModSpec.Version != "" && dep.Source.ModSpec.Name != "" { - sb.WriteString(dep.Source.MarshalTOML()) - } else { - sb.WriteString(fmt.Sprintf(DEP_PATTERN, dep.Name, dep.Source.MarshalTOML())) + depName := dep.Name + if !dep.Source.ModSpec.IsNil() { + if dep.Source.ModSpec.Alias != "" { + depName = dep.Source.ModSpec.Alias + } } + sb.WriteString(fmt.Sprintf(DEP_PATTERN, depName, dep.Source.MarshalTOML())) return sb.String() } @@ -231,6 +233,11 @@ func (deps *Dependencies) UnmarshalModTOML(data interface{}) error { if err != nil { return err } + if !dep.Source.ModSpec.IsNil() { + if dep.Source.ModSpec.Name != dep.Name { + dep.Source.ModSpec.Alias = dep.Name + } + } deps.Deps.Set(k, dep) } diff --git a/pkg/package/toml_test.go b/pkg/package/toml_test.go index 545b4300..cfbd9034 100644 --- a/pkg/package/toml_test.go +++ b/pkg/package/toml_test.go @@ -361,3 +361,21 @@ func TestInitEmptyPkg(t *testing.T) { fmt.Printf("modfile: '%q'\n", got_data) assert.Equal(t, expected_toml, got_data) } + +func TestUnMarshalRename(t *testing.T) { + modfile := ModFile{} + modfile.LoadModFile(filepath.Join(getTestDir("test_rename_pkg"), "kcl.mod")) + assert.Equal(t, modfile.Pkg.Name, "rename") + assert.Equal(t, modfile.Pkg.Version, "0.0.1") + assert.Equal(t, modfile.Pkg.Edition, "v0.10.0") + assert.Equal(t, modfile.Dependencies.Deps.Len(), 1) + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).Name, "newpkg") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).FullName, "newpkg_0.0.1") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).Version, "0.0.1") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).Source.ModSpec.Name, "subhelloworld") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).Source.ModSpec.Version, "0.0.1") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).Source.ModSpec.Alias, "newpkg") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).Oci.Reg, "ghcr.io") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).Oci.Repo, "kcl-lang/helloworld") + assert.Equal(t, modfile.Dependencies.Deps.GetOrDefault("newpkg", TestPkgDependency).Oci.Tag, "0.1.4") +}