Skip to content

Commit

Permalink
Merge pull request #543 from kcl-lang/find-submod-by-spec
Browse files Browse the repository at this point in the history
feat: supports add submod by ModSpec
  • Loading branch information
Peefy authored Nov 13, 2024
2 parents 6b2c011 + 6ffa568 commit c99c0f5
Show file tree
Hide file tree
Showing 18 changed files with 172 additions and 8 deletions.
16 changes: 16 additions & 0 deletions pkg/client/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ func TestAddWithModSpec(t *testing.T) {
"adding dependency 'cc'" +
"add dependency 'cc:0.0.1' successfully",
},
{
name: "TestAddGitWithoutModFileWithModSpec",
pkgSubPath: "git_mod_2",
sourceUrl: "git://github.com/kcl-lang/flask-demo-kcl-manifests.git?commit=3adfc81&mod=cc",
msg: "cloning 'https://github.com/kcl-lang/flask-demo-kcl-manifests.git' with commit '3adfc81'" +
"adding dependency 'cc'" +
"add dependency 'cc:0.0.2' successfully",
},
{
name: "TestAddGitWithoutModFileWithModSpec",
pkgSubPath: "git_mod_3",
sourceUrl: "git://github.com/kcl-lang/flask-demo-kcl-manifests.git?commit=3adfc81&mod=cc:0.0.1",
msg: "cloning 'https://github.com/kcl-lang/flask-demo-kcl-manifests.git' with commit '3adfc81'" +
"adding dependency 'cc'" +
"add dependency 'cc:0.0.1' successfully",
},
{
name: "TestAddLocalWithModSpec",
pkgSubPath: filepath.Join("local", "pkg"),
Expand Down
2 changes: 1 addition & 1 deletion pkg/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2013,7 +2013,7 @@ func testRunRemoteWithArgsInvalid(t *testing.T) {
{
sourceURL: "git://github.com/kcl-lang/flask-demo-kcl-manifests?commit=8308200&mod=cc:0.0.2",
expectedLog: "cloning 'https://github.com/kcl-lang/flask-demo-kcl-manifests' with commit '8308200'\n",
expectedErrMsg: "version mismatch: 0.0.1 != 0.0.2, version 0.0.2 not found",
expectedErrMsg: "kcl.mod with package 'cc:0.0.2' not found",
},
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/client/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func testPullWithModSpec(t *testing.T) {
WithLocalPath(pulledPath),
WithPullSourceUrl("oci://ghcr.io/kcl-lang/helloworld?tag=0.1.4&mod=subhelloworld:0.0.2"),
)
assert.Equal(t, err.Error(), "version mismatch: 0.0.1 != 0.0.2, version 0.0.2 not found")
assert.Equal(t, err.Error(), "kcl.mod with package 'subhelloworld:0.0.2' not found")
}

func testPullWithOnlySpec(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/client/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ func (o *RunOptions) applyCompileOptions(source downloader.Source, kclPkg *pkg.K
// use the subdirectories specified by 'ModSpec'
var err error
if pkgSource.ModSpec != nil && pkgSource.ModSpec.Name != "" {
sourcePath, err = utils.FindPackage(sourcePath, pkgSource.ModSpec.Name)
sourcePath, err = downloader.FindPackageByModSpec(sourcePath, pkgSource.ModSpec)
if err != nil {
return false
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/client/test_data/add_with_mod_spec/git_mod_2/kcl.mod.bk
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "git"
edition = "v0.10.0"
version = "0.0.1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "git"
edition = "v0.10.0"
version = "0.0.1"

[dependencies]
cc = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git", commit = "3adfc81", version = "0.0.2" }
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[dependencies]
[dependencies.cc]
name = "cc"
full_name = "cc_0.0.2"
version = "0.0.2"
url = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git"
commit = "3adfc81"
1 change: 1 addition & 0 deletions pkg/client/test_data/add_with_mod_spec/git_mod_2/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The_first_kcl_program = 'Hello World!'
4 changes: 4 additions & 0 deletions pkg/client/test_data/add_with_mod_spec/git_mod_3/kcl.mod.bk
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "git"
edition = "v0.10.0"
version = "0.0.1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "git"
edition = "v0.10.0"
version = "0.0.1"

[dependencies]
cc = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git", commit = "3adfc81", version = "0.0.1" }
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[dependencies]
[dependencies.cc]
name = "cc"
full_name = "cc_0.0.1"
version = "0.0.1"
url = "https://github.com/kcl-lang/flask-demo-kcl-manifests.git"
commit = "3adfc81"
1 change: 1 addition & 0 deletions pkg/client/test_data/add_with_mod_spec/git_mod_3/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The_first_kcl_program = 'Hello World!'
110 changes: 110 additions & 0 deletions pkg/downloader/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package downloader

import (
"fmt"
"os"
"path/filepath"

"github.com/BurntSushi/toml"
"github.com/hashicorp/go-version"
"kcl-lang.io/kpm/pkg/constants"
"kcl-lang.io/kpm/pkg/utils"
)

func loadModSpecFromKclMod(kclModPath string) (*ModSpec, error) {
type Package struct {
Name string `toml:"name"`
Version string `toml:"version"`
}
type ModFile struct {
Package Package `toml:"package"`
}

var modFile ModFile
_, err := toml.DecodeFile(kclModPath, &modFile)
if err != nil {
return nil, err
}

return &ModSpec{
Name: modFile.Package.Name,
Version: modFile.Package.Version,
}, nil
}

// MatchesPackageName checks whether the package name in the kcl.mod file under 'kclModPath' is equal to 'targetPackage'.
func matchesPackageSpec(kclModPath string, modSpec *ModSpec) bool {
type Package struct {
Name string `toml:"name"`
Version string `toml:"version"`
}
type ModFile struct {
Package Package `toml:"package"`
}

var modFile ModFile
_, err := toml.DecodeFile(kclModPath, &modFile)
if err != nil {
fmt.Printf("Error parsing kcl.mod file: %v\n", err)
return false
}

return modFile.Package.Name == modSpec.Name && modFile.Package.Version == modSpec.Version
}

func FindPackageByModSpec(root string, modSpec *ModSpec) (string, error) {
var result string
var modVersion string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
kclModPath := filepath.Join(path, constants.KCL_MOD)
if _, err := os.Stat(kclModPath); err == nil {
// If the package name and version are specified,
// we can directly check if the kcl.mod file matches the package.
if matchesPackageSpec(kclModPath, modSpec) {
result = path
return filepath.SkipAll
} else if modSpec.Version == "" {
// If the package name specified, but version are not specified,
if utils.MatchesPackageName(kclModPath, modSpec.Name) {
// load the version from the kcl.mod file
tmpSpec, err := loadModSpecFromKclMod(kclModPath)
if err != nil {
return err
}
// Remember the local path with the highest version
tmpVer, err := version.NewSemver(tmpSpec.Version)
if err != nil {
return err
}
if modVersion != "" {
modVer, err := version.NewSemver(modVersion)
if err != nil {
return err
}
if tmpVer.GreaterThan(modVer) {
modVersion = tmpSpec.Version
result = path
}
} else {
modVersion = tmpSpec.Version
result = path
}
}
}
}
}
return nil
})

if err != nil {
return "", err
}
if result == "" {
return "", fmt.Errorf("kcl.mod with package '%s:%s' not found", modSpec.Name, modSpec.Version)
}
return result, nil
}
4 changes: 2 additions & 2 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ func FindPackage(root, targetPackage string) (string, error) {
if info.IsDir() {
kclModPath := filepath.Join(path, constants.KCL_MOD)
if _, err := os.Stat(kclModPath); err == nil {
if matchesPackageName(kclModPath, targetPackage) {
if MatchesPackageName(kclModPath, targetPackage) {
result = path
return filepath.SkipAll
}
Expand All @@ -622,7 +622,7 @@ func FindPackage(root, targetPackage string) (string, error) {
}

// MatchesPackageName checks whether the package name in the kcl.mod file under 'kclModPath' is equal to 'targetPackage'.
func matchesPackageName(kclModPath, targetPackage string) bool {
func MatchesPackageName(kclModPath, targetPackage string) bool {
type Package struct {
Name string `toml:"name"`
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func TestFindPackage(t *testing.T) {

func TestMatchesPackageName(t *testing.T) {
address := filepath.Join(getTestDir("test_find_package"), "test_2", "kcl.mod")
assert.Equal(t, matchesPackageName(address, "test_find_package"), true)
assert.Equal(t, MatchesPackageName(address, "test_find_package"), true)
}

func TestShortHash(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions pkg/visitor/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (pv *PkgVisitor) Visit(s *downloader.Source, v visitFunc) error {
}

if s.ModSpec != nil && s.ModSpec.Name != "" {
modPath, err = utils.FindPackage(modPath, s.ModSpec.Name)
modPath, err = downloader.FindPackageByModSpec(modPath, s.ModSpec)
if err != nil {
return err
}
Expand Down Expand Up @@ -242,7 +242,7 @@ func (rv *RemoteVisitor) Visit(s *downloader.Source, v visitFunc) error {
return err
}
if !s.ModSpec.IsNil() {
modFullPath, err = utils.FindPackage(modFullPath, s.ModSpec.Name)
modFullPath, err = downloader.FindPackageByModSpec(modFullPath, s.ModSpec)
if err != nil {
return err
}
Expand Down

0 comments on commit c99c0f5

Please sign in to comment.