diff --git a/pkg/client/client.go b/pkg/client/client.go index 946ddf51..d60117ee 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -650,6 +650,7 @@ func (c *KpmClient) CompileGitPkg(gitOpts *git.CloneOptions, compileOpts *opt.Co git.WithCommit(gitOpts.Commit), git.WithBranch(gitOpts.Branch), git.WithTag(gitOpts.Tag), + git.WithSubPackage(gitOpts.SubPackage), git.WithRepoURL(gitOpts.RepoURL), git.WithLocalPath(tmpDir), ) @@ -1286,6 +1287,10 @@ func (c *KpmClient) DownloadFromGit(dep *downloader.Git, localPath string) (stri msg = fmt.Sprintf("with commit '%s'", dep.Commit) } + if len(dep.SubPackage) != 0 { + msg = fmt.Sprintf("with subpackage '%s'", dep.SubPackage) + } + if len(dep.Branch) != 0 { msg = fmt.Sprintf("with branch '%s'", dep.Branch) } @@ -1299,6 +1304,7 @@ func (c *KpmClient) DownloadFromGit(dep *downloader.Git, localPath string) (stri git.WithCommit(dep.Commit), git.WithTag(dep.Tag), git.WithRepoURL(dep.Url), + git.WithSubPackage(dep.SubPackage), git.WithLocalPath(localPath), git.WithWriter(c.logWriter), ) diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 9b4bac72..3153e42b 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -1136,7 +1136,7 @@ func TestRunGit(t *testing.T) { testPath := getTestDir("test_run_git") opts := opt.DefaultCompileOptions() - gitOpts := git.NewCloneOptions("https://github.com/KusionStack/catalog", "", "0.1.2", "", filepath.Join(testPath, "catalog"), nil) + gitOpts := git.NewCloneOptions("https://github.com/KusionStack/catalog", "", "0.1.2", "", "", filepath.Join(testPath, "catalog"), nil) defer func() { _ = os.RemoveAll(filepath.Join(testPath, "catalog")) }() @@ -1526,7 +1526,7 @@ func TestRunGitWithLocalDep(t *testing.T) { expectPath := filepath.Join(testPath, tc.expectFile) opts := opt.DefaultCompileOptions() - gitOpts := git.NewCloneOptions("https://github.com/kcl-lang/flask-demo-kcl-manifests.git", tc.ref, "", "", "", nil) + gitOpts := git.NewCloneOptions("https://github.com/kcl-lang/flask-demo-kcl-manifests.git", tc.ref, "", "", "", "", nil) result, err := kpmcli.CompileGitPkg(gitOpts, opts) assert.Equal(t, err, nil) diff --git a/pkg/cmd/cmd_add.go b/pkg/cmd/cmd_add.go index 30761bdf..ca85103e 100644 --- a/pkg/cmd/cmd_add.go +++ b/pkg/cmd/cmd_add.go @@ -45,9 +45,9 @@ func NewAddCmd(kpmcli *client.KpmClient) *cli.Command { Name: "rename", Usage: "rename the package name in kcl.mod.lock", }, - &cli.StringSliceFlag{ - Name: "package", - Usage: "package name to use in case of git", + &cli.StringFlag{ + Name: "sub-package", + Usage: "package name inside a monorepo when using git flag", }, }, @@ -202,11 +202,7 @@ func parseGitRegistryOptions(c *cli.Context) (*opt.RegistryOptions, *reporter.Kp return nil, err } - gitPackage, err := onlyOnceOption(c, "package") - - if err != (*reporter.KpmEvent)(nil) { - return nil, err - } + gitSubPackage := c.String("sub-package") if gitUrl == "" { return nil, reporter.NewErrorEvent(reporter.InvalidGitUrl, fmt.Errorf("the argument 'git' is required")) @@ -218,10 +214,10 @@ func parseGitRegistryOptions(c *cli.Context) (*opt.RegistryOptions, *reporter.Kp return &opt.RegistryOptions{ Git: &opt.GitOptions{ - Url: gitUrl, - Tag: gitTag, - Commit: gitCommit, - Package: gitPackage, + Url: gitUrl, + Tag: gitTag, + Commit: gitCommit, + SubPackage: gitSubPackage, }, }, nil } diff --git a/pkg/cmd/cmd_run.go b/pkg/cmd/cmd_run.go index 4564e5d5..a31a04d4 100644 --- a/pkg/cmd/cmd_run.go +++ b/pkg/cmd/cmd_run.go @@ -143,7 +143,7 @@ func KpmRun(c *cli.Context, kpmcli *client.KpmClient) error { // 'kpm run' compile the package from the kcl package tar. compileResult, err = kpmcli.CompileTarPkg(runEntry.PackageSource(), kclOpts) } else if runEntry.IsGit() { - gitOpts := git.NewCloneOptions(runEntry.PackageSource(), "", c.String(FLAG_TAG), "", "", nil) + gitOpts := git.NewCloneOptions(runEntry.PackageSource(), "", c.String(FLAG_TAG), "", "", "", nil) // 'kpm run' compile the package from the git url compileResult, err = kpmcli.CompileGitPkg(gitOpts, kclOpts) } else { diff --git a/pkg/downloader/downloader.go b/pkg/downloader/downloader.go index 2369e3d0..b6bc99ab 100644 --- a/pkg/downloader/downloader.go +++ b/pkg/downloader/downloader.go @@ -230,6 +230,10 @@ func (d *GitDownloader) Download(opts DownloadOptions) error { msg = fmt.Sprintf("with branch '%s'", opts.Source.Git.Branch) } + if len(opts.Source.Git.SubPackage) != 0 { + msg = fmt.Sprintf("with sub-package '%s'", opts.Source.Git.SubPackage) + } + reporter.ReportMsgTo( fmt.Sprintf("cloning '%s' %s", opts.Source.Git.Url, msg), opts.LogWriter, @@ -244,6 +248,7 @@ func (d *GitDownloader) Download(opts DownloadOptions) error { git.WithCommit(gitSource.Commit), git.WithBranch(gitSource.Branch), git.WithTag(gitSource.Tag), + git.WithSubPackage(gitSource.SubPackage), git.WithRepoURL(gitSource.Url), git.WithLocalPath(opts.LocalPath), ) diff --git a/pkg/downloader/source.go b/pkg/downloader/source.go index 2576bbee..aee39bf4 100644 --- a/pkg/downloader/source.go +++ b/pkg/downloader/source.go @@ -34,12 +34,12 @@ type Oci struct { // Git is the package source from git registry. type Git struct { - Url string `toml:"url,omitempty"` - Branch string `toml:"branch,omitempty"` - Commit string `toml:"commit,omitempty"` - Tag string `toml:"git_tag,omitempty"` - Version string `toml:"version,omitempty"` - Package string `toml:"package,omitempty"` + Url string `toml:"url,omitempty"` + Branch string `toml:"branch,omitempty"` + Commit string `toml:"commit,omitempty"` + SubPackage string `toml:"sub-package,omitempty"` + Tag string `toml:"git_tag,omitempty"` + Version string `toml:"version,omitempty"` } type Registry struct { diff --git a/pkg/downloader/toml.go b/pkg/downloader/toml.go index 565c4b34..9dc70615 100644 --- a/pkg/downloader/toml.go +++ b/pkg/downloader/toml.go @@ -67,6 +67,7 @@ func (registry *Registry) MarshalTOML() string { const GIT_URL_PATTERN = "git = \"%s\"" const TAG_PATTERN = "tag = \"%s\"" const GIT_COMMIT_PATTERN = "commit = \"%s\"" +const GIT_SUB_PACKAGE_PATTERN = "sub-package = \"%s\"" const GIT_BRANCH_PATTERN = "branch = \"%s\"" const VERSION_PATTERN = "version = \"%s\"" const GIT_PACKAGE = "package = \"%s\"" @@ -86,6 +87,11 @@ func (git *Git) MarshalTOML() string { sb.WriteString(fmt.Sprintf(GIT_COMMIT_PATTERN, git.Commit)) } + if len(git.SubPackage) != 0 { + sb.WriteString(SEPARATOR) + sb.WriteString(fmt.Sprintf(GIT_SUB_PACKAGE_PATTERN, git.SubPackage)) + } + if len(git.Branch) != 0 { sb.WriteString(SEPARATOR) sb.WriteString(fmt.Sprintf(GIT_BRANCH_PATTERN, git.Branch)) @@ -181,6 +187,7 @@ func (source *Source) UnmarshalModTOML(data interface{}) error { const GIT_URL_FLAG = "git" const TAG_FLAG = "tag" const GIT_COMMIT_FLAG = "commit" +const GIT_SUB_PACKAGE_flag = "sub-package" const GIT_BRANCH_FLAG = "branch" const GIT_PACKAGE_FLAG = "package" @@ -202,6 +209,10 @@ func (git *Git) UnmarshalModTOML(data interface{}) error { git.Commit = v } + if v, ok := meta[GIT_SUB_PACKAGE_PATTERN].(string); ok { + git.SubPackage = v + } + if v, ok := meta[GIT_BRANCH_FLAG].(string); ok { git.Branch = v } diff --git a/pkg/git/getter.go b/pkg/git/getter.go index e9472fce..3141eb8d 100644 --- a/pkg/git/getter.go +++ b/pkg/git/getter.go @@ -3,39 +3,36 @@ package git import ( "fmt" - - "github.com/hashicorp/go-getter" "kcl-lang.io/kpm/pkg/constants" ) -var goGetterGetters = map[string]getter.Getter{ - "git": new(getter.GitGetter), -} - -var goGetterNoDetectors = []getter.Detector{} - const GIT_PROTOCOL = "git::" func ForceProtocol(url, protocol string) string { return protocol + url } -// ForceGitUrl will add the branch, tag or commit to the git URL and force it to the git protocol -// `` will return `Git::?ref=` +// ForceGitUrl will add the subpackage and branch, tag or commit to the git URL and force it to the git protocol +// `` will return `Git:://?ref=` func (cloneOpts *CloneOptions) ForceGitUrl() (string, error) { if err := cloneOpts.Validate(); err != nil { return "", nil } + newRepoUrl := cloneOpts.RepoURL + if cloneOpts.SubPackage != "" { + newRepoUrl += "//" + cloneOpts.SubPackage + } + var attributes = []string{cloneOpts.Branch, cloneOpts.Commit, cloneOpts.Tag} for _, attr := range attributes { if attr != "" { return ForceProtocol( - cloneOpts.RepoURL+fmt.Sprintf(constants.GIT_PROTOCOL_URL_PATTERN, attr), + newRepoUrl+fmt.Sprintf(constants.GIT_PROTOCOL_URL_PATTERN, attr), GIT_PROTOCOL, ), nil } } - return ForceProtocol(cloneOpts.RepoURL, GIT_PROTOCOL), nil + return ForceProtocol(newRepoUrl, GIT_PROTOCOL), nil } diff --git a/pkg/git/git.go b/pkg/git/git.go index 6ece5128..de4f041a 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -18,26 +18,28 @@ import ( // CloneOptions is a struct for specifying options for cloning a git repository type CloneOptions struct { - RepoURL string - Commit string - Tag string - Branch string - LocalPath string - Writer io.Writer - Bare bool // New field to indicate if the clone should be bare + RepoURL string + Commit string + Tag string + SubPackage string + Branch string + LocalPath string + Writer io.Writer + Bare bool // New field to indicate if the clone should be bare } // CloneOption is a function that modifies CloneOptions type CloneOption func(*CloneOptions) -func NewCloneOptions(repoUrl, commit, tag, branch, localpath string, Writer io.Writer) *CloneOptions { +func NewCloneOptions(repoUrl, commit, tag, subpackage, branch, localpath string, Writer io.Writer) *CloneOptions { return &CloneOptions{ - RepoURL: repoUrl, - Commit: commit, - Tag: tag, - Branch: branch, - LocalPath: localpath, - Writer: Writer, + RepoURL: repoUrl, + Commit: commit, + Tag: tag, + SubPackage: subpackage, + Branch: branch, + LocalPath: localpath, + Writer: Writer, } } @@ -69,6 +71,13 @@ func WithCommit(commit string) CloneOption { } } +// WithSubPackage sets the subpackage for CloneOptions +func WithSubPackage(subpackage string) CloneOption { + return func(o *CloneOptions) { + o.SubPackage = subpackage + } +} + // WithTag sets the tag for CloneOptions func WithTag(tag string) CloneOption { return func(o *CloneOptions) { @@ -93,6 +102,7 @@ func WithWriter(writer io.Writer) CloneOption { // Validate checks if the CloneOptions are valid func (cloneOpts *CloneOptions) Validate() error { onlyOneAllowed := 0 + onlyOnePackageAllowed := 0 if cloneOpts.Branch != "" { onlyOneAllowed++ } @@ -102,10 +112,16 @@ func (cloneOpts *CloneOptions) Validate() error { if cloneOpts.Commit != "" { onlyOneAllowed++ } + if cloneOpts.SubPackage != "" { + onlyOnePackageAllowed++ + } if onlyOneAllowed > 1 { return errors.New("only one of branch, tag or commit is allowed") } + if onlyOnePackageAllowed > 1 { + return errors.New("only one subpackage is allowed") + } return nil } @@ -172,22 +188,17 @@ func (cloneOpts *CloneOptions) Clone() (*git.Repository, error) { return nil, err } - client := &getter.Client{ - Src: url, - Dst: cloneOpts.LocalPath, - Pwd: cloneOpts.LocalPath, - Mode: getter.ClientModeDir, - Detectors: goGetterNoDetectors, - Getters: goGetterGetters, - } - - if err := client.Get(); err != nil { + if err := getter.GetAny(cloneOpts.LocalPath, url); err != nil { return nil, err } - repo, err := git.PlainOpen(cloneOpts.LocalPath) - if err != nil { - return nil, err + repo := &git.Repository{} + + if cloneOpts.SubPackage == "" { + repo, err = git.PlainOpen(cloneOpts.LocalPath) + if err != nil { + return nil, err + } } return repo, nil diff --git a/pkg/git/git_test.go b/pkg/git/git_test.go index 7625b409..833132d6 100644 --- a/pkg/git/git_test.go +++ b/pkg/git/git_test.go @@ -31,10 +31,11 @@ func TestWithGitOptions(t *testing.T) { } func TestNewCloneOptions(t *testing.T) { - cloneOpts := NewCloneOptions("https://github.com/kcl-lang/kcl", "", "v1.0.0", "", "", nil) + cloneOpts := NewCloneOptions("https://github.com/kcl-lang/kcl", "", "v1.0.0", "", "", "", nil) assert.Equal(t, cloneOpts.RepoURL, "https://github.com/kcl-lang/kcl") assert.Equal(t, cloneOpts.Tag, "v1.0.0") assert.Equal(t, cloneOpts.Commit, "") + assert.Equal(t, cloneOpts.SubPackage, "") assert.Equal(t, cloneOpts.Branch, "") assert.Equal(t, cloneOpts.LocalPath, "") assert.Equal(t, cloneOpts.Writer, nil) diff --git a/pkg/opt/opt.go b/pkg/opt/opt.go index 02309a55..ef4b20b6 100644 --- a/pkg/opt/opt.go +++ b/pkg/opt/opt.go @@ -378,11 +378,11 @@ func ParseLocalPathOptions(localPath string) (*LocalOptions, *reporter.KpmEvent) } type GitOptions struct { - Url string - Branch string - Commit string - Tag string - Package string + Url string + Branch string + Commit string + Tag string + SubPackage string } func (opts *GitOptions) Validate() error { diff --git a/pkg/package/modfile.go b/pkg/package/modfile.go index 0f72cf32..f69e4533 100644 --- a/pkg/package/modfile.go +++ b/pkg/package/modfile.go @@ -482,11 +482,11 @@ func (deps *Dependencies) loadLockFile(filepath string) error { func ParseOpt(opt *opt.RegistryOptions) (*Dependency, error) { if opt.Git != nil { gitSource := downloader.Git{ - Url: opt.Git.Url, - Branch: opt.Git.Branch, - Commit: opt.Git.Commit, - Tag: opt.Git.Tag, - Package: opt.Git.Package, + Url: opt.Git.Url, + Branch: opt.Git.Branch, + Commit: opt.Git.Commit, + Tag: opt.Git.Tag, + SubPackage: opt.Git.SubPackage, } gitRef, err := gitSource.GetValidGitReference()