Skip to content

Commit

Permalink
Merge pull request #144 from zong-zhe/kpm-add-local
Browse files Browse the repository at this point in the history
feat: 'kpm add' supports local path.
  • Loading branch information
Peefy authored Aug 1, 2023
2 parents e104bef + 1a6d48c commit 30c41ca
Show file tree
Hide file tree
Showing 266 changed files with 587 additions and 141 deletions.
56 changes: 48 additions & 8 deletions pkg/cmd/cmd_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package cmd
import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/urfave/cli/v2"
Expand Down Expand Up @@ -86,6 +87,19 @@ func KpmAdd(c *cli.Context) error {
return err
}

if addOpts.RegistryOpts.Local != nil {
absAddPath, err := filepath.Abs(addOpts.RegistryOpts.Local.Path)
if err != nil {
return reporter.NewErrorEvent(reporter.Bug, err, "internal bugs, please contact us to fix it.")
}
if absAddPath == kclPkg.HomePath {
return reporter.NewErrorEvent(
reporter.AddItselfAsDep,
fmt.Errorf("cannot add '%s' as a dependency to itself", kclPkg.GetPkgName()),
)
}
}

err = addOpts.Validate()
if err != nil {
return err
Expand Down Expand Up @@ -126,15 +140,23 @@ func parseAddOptions(c *cli.Context, localPath string) (*opt.AddOptions, error)
RegistryOpts: *gitOpts,
}, nil
} else {
// parse from 'kpm add xxx:0.0.1'.
ociReg, err := parseOciRegistryOptions(c)
if err != nil {
return nil, err
localPkg, err := parseLocalPathOptions(c)
if err != (*reporter.KpmEvent)(nil) {
// parse from 'kpm add xxx:0.0.1'.
ociReg, err := parseOciRegistryOptions(c)
if err != nil {
return nil, err
}
return &opt.AddOptions{
LocalPath: localPath,
RegistryOpts: *ociReg,
}, nil
} else {
return &opt.AddOptions{
LocalPath: localPath,
RegistryOpts: *localPkg,
}, nil
}
return &opt.AddOptions{
LocalPath: localPath,
RegistryOpts: *ociReg,
}, nil
}
}

Expand Down Expand Up @@ -191,6 +213,24 @@ func parseOciRegistryOptions(c *cli.Context) (*opt.RegistryOptions, error) {
}, nil
}

// parseLocalPathOptions will parse the local path information from user cli inputs.
func parseLocalPathOptions(c *cli.Context) (*opt.RegistryOptions, *reporter.KpmEvent) {
localPath := c.Args().First()
if localPath == "" {
return nil, reporter.NewErrorEvent(reporter.PathIsEmpty, errors.PathIsEmpty)
}
// check if the local path exists.
if _, err := os.Stat(localPath); os.IsNotExist(err) {
return nil, reporter.NewErrorEvent(reporter.LocalPathNotExist, err)
} else {
return &opt.RegistryOptions{
Local: &opt.LocalOptions{
Path: localPath,
},
}, nil
}
}

// parseOciPkgNameAndVersion will parse package name and version
// from string "<pkg_name>:<pkg_version>".
func parseOciPkgNameAndVersion(s string) (string, string, error) {
Expand Down
3 changes: 2 additions & 1 deletion pkg/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ var IsOciRef = errors.New("kpm: oci ref is not an url.")

// Invalid Version
var InvalidVersionFormat = errors.New("kpm: failed to parse version.")

var PathNotFound = errors.New("path not found.")
var PathIsEmpty = errors.New("path is empty.")
var InvalidPkg = errors.New("invalid kcl package.")
var InvalidOciUrl = errors.New("invalid oci url.")
var UnknownEnv = errors.New("invalid environment variable.")
1 change: 1 addition & 0 deletions pkg/oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type OciClient struct {
func NewOciClient(regName, repoName string) (*OciClient, error) {
repoPath := utils.JoinPath(regName, repoName)
repo, err := remote.NewRepository(repoPath)

if err != nil {
return nil, reporter.NewErrorEvent(
reporter.RepoNotFound,
Expand Down
24 changes: 22 additions & 2 deletions pkg/opt/opt.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package opt

import (
"net/url"
"os"
"path/filepath"
"strings"

Expand Down Expand Up @@ -39,13 +40,16 @@ func (opts *AddOptions) Validate() error {
return opts.RegistryOpts.Git.Validate()
} else if opts.RegistryOpts.Oci != nil {
return opts.RegistryOpts.Oci.Validate()
} else if opts.RegistryOpts.Local != nil {
return opts.RegistryOpts.Local.Validate()
}
return nil
}

type RegistryOptions struct {
Git *GitOptions
Oci *OciOptions
Git *GitOptions
Oci *OciOptions
Local *LocalOptions
}

type GitOptions struct {
Expand Down Expand Up @@ -78,6 +82,22 @@ func (opts *OciOptions) Validate() error {
return nil
}

// LocalOptions for local packages.
// kpm will find packages from local path.
type LocalOptions struct {
Path string
}

func (opts *LocalOptions) Validate() error {
if len(opts.Path) == 0 {
return errors.PathIsEmpty
}
if _, err := os.Stat(opts.Path); err != nil {
return err
}
return nil
}

const OCI_SEPARATOR = ":"

// ParseOciOptionFromString will parser '<repo_name>:<repo_tag>' into an 'OciOptions' with an OCI registry.
Expand Down
39 changes: 35 additions & 4 deletions pkg/mod/modfile.go → pkg/package/modfile.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright 2022 The KCL Authors. All rights reserved.
package modfile
package pkg

import (
"fmt"
Expand Down Expand Up @@ -101,6 +101,10 @@ type Dependency struct {
Source `json:"-"`
}

func (dep *Dependency) isFromLocal() bool {
return dep.Source.Oci == nil && dep.Source.Git == nil && dep.Source.Local != nil
}

// FillDepInfo will fill registry information for a dependency.
func (dep *Dependency) FillDepInfo() error {
if dep.Source.Oci != nil {
Expand Down Expand Up @@ -144,6 +148,10 @@ func (dep *Dependency) Download(localPath string) (*Dependency, error) {
dep.FullName = dep.GenDepFullName()
}

if dep.Source.Local != nil {
dep.LocalFullPath = dep.Source.Local.Path
}

var err error
dep.Sum, err = utils.HashDir(dep.LocalFullPath)
if err != nil {
Expand Down Expand Up @@ -259,6 +267,11 @@ func (dep *Oci) Download(localPath string) (string, error) {
type Source struct {
*Git
*Oci
*Local
}

type Local struct {
Path string `toml:"path,omitempty"`
}

type Oci struct {
Expand Down Expand Up @@ -396,7 +409,7 @@ func (deps *Dependencies) loadLockFile(filepath string) error {
}

// Parse out some information for a Dependency from registry url.
func ParseOpt(opt *opt.RegistryOptions) *Dependency {
func ParseOpt(opt *opt.RegistryOptions) (*Dependency, error) {
if opt.Git != nil {
gitSource := Git{
Url: opt.Git.Url,
Expand All @@ -412,7 +425,7 @@ func ParseOpt(opt *opt.RegistryOptions) *Dependency {
Git: &gitSource,
},
Version: gitSource.Tag,
}
}, nil
}
if opt.Oci != nil {
repoPath := utils.JoinPath(opt.Oci.Repo, opt.Oci.PkgName)
Expand All @@ -429,9 +442,27 @@ func ParseOpt(opt *opt.RegistryOptions) *Dependency {
Oci: &ociSource,
},
Version: opt.Oci.Tag,
}, nil
}
if opt.Local != nil {
depPkg, err := LoadKclPkg(opt.Local.Path)
if err != nil {
return nil, err
}
return &Dependency{
Name: depPkg.modFile.Pkg.Name,
FullName: depPkg.modFile.Pkg.Name + "_" + depPkg.modFile.Pkg.Version,
LocalFullPath: opt.Local.Path,
Source: Source{
Local: &Local{
Path: opt.Local.Path,
},
},
Version: depPkg.modFile.Pkg.Version,
}, nil

}
return nil
return nil, nil
}

const PKG_NAME_PATTERN = "%s_%s"
Expand Down
25 changes: 3 additions & 22 deletions pkg/mod/modfile_test.go → pkg/package/modfile_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package modfile
package pkg

import (
"os"
Expand All @@ -11,25 +11,6 @@ import (
"kcl-lang.io/kpm/pkg/utils"
)

const testDataDir = "test_data"

func getTestDir(subDir string) string {
pwd, _ := os.Getwd()
testDir := filepath.Join(pwd, testDataDir)
testDir = filepath.Join(testDir, subDir)

return testDir
}

func initTestDir(subDir string) string {
testDir := getTestDir(subDir)
// clean the test data
_ = os.RemoveAll(testDir)
_ = os.Mkdir(testDir, 0755)

return testDir
}

func TestModFileExists(t *testing.T) {
testDir := initTestDir("test_data_modfile")
// there is no 'kcl.mod' and 'kcl.mod.lock'.
Expand Down Expand Up @@ -74,15 +55,15 @@ func TestModFileExists(t *testing.T) {

func TestParseOpt(t *testing.T) {

dep := ParseOpt(&opt.RegistryOptions{
dep, err := ParseOpt(&opt.RegistryOptions{
Git: &opt.GitOptions{
Url: "test.git",
Branch: "test_branch",
Commit: "test_commit",
Tag: "test_tag",
},
})

assert.Equal(t, err, nil)
assert.Equal(t, dep.Name, "test")
assert.Equal(t, dep.FullName, "test_test_tag")
assert.Equal(t, dep.Url, "test.git")
Expand Down
Loading

0 comments on commit 30c41ca

Please sign in to comment.