Skip to content

Commit efc7b9c

Browse files
authored
Merge pull request #376 from zong-zhe/unify-pull-api
feat: add unified api for CLI pull command
2 parents ebf591f + bb045eb commit efc7b9c

File tree

20 files changed

+1129
-406
lines changed

20 files changed

+1129
-406
lines changed

go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/distribution/reference v0.6.0
1111
github.com/dominikbraun/graph v0.23.0
1212
github.com/elliotchance/orderedmap/v2 v2.2.0
13+
github.com/google/uuid v1.6.0
1314
github.com/opencontainers/image-spec v1.1.0
1415
github.com/otiai10/copy v1.14.0
1516
github.com/sirupsen/logrus v1.9.3
@@ -74,7 +75,6 @@ require (
7475
github.com/google/go-cmp v0.6.0 // indirect
7576
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
7677
github.com/google/s2a-go v0.1.7 // indirect
77-
github.com/google/uuid v1.6.0 // indirect
7878
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
7979
github.com/googleapis/gax-go/v2 v2.12.2 // indirect
8080
github.com/gorilla/mux v1.8.1 // indirect
@@ -145,7 +145,6 @@ require (
145145

146146
require (
147147
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
148-
github.com/elliotchance/orderedmap v1.6.0
149148
github.com/go-git/go-git/v5 v5.11.0
150149
github.com/gofrs/flock v0.8.1
151150
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,6 @@ github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucV
314314
github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc=
315315
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
316316
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
317-
github.com/elliotchance/orderedmap v1.6.0 h1:xjn+kbbKXeDq6v9RVE+WYwRbYfAZKvlWfcJNxM8pvEw=
318-
github.com/elliotchance/orderedmap v1.6.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
319317
github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk=
320318
github.com/elliotchance/orderedmap/v2 v2.2.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q=
321319
github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY=

pkg/api/kpm_run_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/elliotchance/orderedmap/v2"
1212
"github.com/stretchr/testify/assert"
1313
"kcl-lang.io/kcl-go/pkg/kcl"
14+
"kcl-lang.io/kpm/pkg/downloader"
1415
"kcl-lang.io/kpm/pkg/opt"
1516
pkg "kcl-lang.io/kpm/pkg/package"
1617
"kcl-lang.io/kpm/pkg/utils"
@@ -266,8 +267,8 @@ func TestStoreModAndModLockFile(t *testing.T) {
266267
Version: "0.0.1",
267268
Sum: "sLr3e6W4RPrXYyswdOSiKqkHes1QHX2tk6SwxAPDqqo=",
268269
LocalFullPath: filepath.Join(testPath, "dep1_0.0.1"),
269-
Source: pkg.Source{
270-
Oci: &pkg.Oci{
270+
Source: downloader.Source{
271+
Oci: &downloader.Oci{
271272
Reg: "ghcr.io",
272273
Repo: "kcl-lang/dep1",
273274
Tag: "0.0.1",

pkg/client/client.go

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ func (c *KpmClient) FillDependenciesInfo(modFile *pkg.ModFile) error {
952952
}
953953

954954
// AcquireTheLatestOciVersion will acquire the latest version of the OCI reference.
955-
func (c *KpmClient) AcquireTheLatestOciVersion(ociSource pkg.Oci) (string, error) {
955+
func (c *KpmClient) AcquireTheLatestOciVersion(ociSource downloader.Oci) (string, error) {
956956
ociClient, err := oci.NewOciClient(ociSource.Reg, ociSource.Repo, &c.settings)
957957
if err != nil {
958958
return "", err
@@ -961,6 +961,64 @@ func (c *KpmClient) AcquireTheLatestOciVersion(ociSource pkg.Oci) (string, error
961961
return ociClient.TheLatestTag()
962962
}
963963

964+
func (c *KpmClient) downloadPkg(options ...downloader.Option) (*pkg.KclPkg, error) {
965+
opts := downloader.DownloadOptions{}
966+
for _, option := range options {
967+
option(&opts)
968+
}
969+
970+
localPath := opts.LocalPath
971+
tmpDir, err := os.MkdirTemp("", "")
972+
if err != nil {
973+
return nil, err
974+
}
975+
tmpDir = filepath.Join(tmpDir, constants.GitScheme)
976+
// clean the temp dir.
977+
defer os.RemoveAll(tmpDir)
978+
err = c.DepDownloader.Download(*downloader.NewDownloadOptions(
979+
downloader.WithLocalPath(tmpDir),
980+
downloader.WithSource(opts.Source),
981+
downloader.WithLogWriter(c.GetLogWriter()),
982+
downloader.WithSettings(*c.GetSettings()),
983+
))
984+
985+
if err != nil {
986+
return nil, err
987+
}
988+
989+
if utils.DirExists(localPath) {
990+
err := os.RemoveAll(localPath)
991+
if err != nil {
992+
return nil, err
993+
}
994+
}
995+
996+
destDir := filepath.Dir(localPath)
997+
if !utils.DirExists(destDir) {
998+
err = os.MkdirAll(destDir, os.ModePerm)
999+
if err != nil {
1000+
return nil, err
1001+
}
1002+
}
1003+
1004+
err = utils.MoveFile(tmpDir, localPath)
1005+
if err != nil {
1006+
return nil, err
1007+
}
1008+
1009+
localPath, err = filepath.Abs(localPath)
1010+
if err != nil {
1011+
return nil, err
1012+
}
1013+
1014+
pkg, err := c.LoadPkgFromPath(localPath)
1015+
if err != nil {
1016+
return nil, err
1017+
}
1018+
1019+
return pkg, nil
1020+
}
1021+
9641022
// Download will download the dependency to the local path.
9651023
func (c *KpmClient) Download(dep *pkg.Dependency, homePath, localPath string) (*pkg.Dependency, error) {
9661024
if dep.Source.Git != nil {
@@ -992,7 +1050,7 @@ func (c *KpmClient) Download(dep *pkg.Dependency, homePath, localPath string) (*
9921050
}
9931051

9941052
if dep.Source.Oci != nil || dep.Source.Registry != nil {
995-
var ociSource *pkg.Oci
1053+
var ociSource *downloader.Oci
9961054
if dep.Source.Oci != nil {
9971055
ociSource = dep.Source.Oci
9981056
} else if dep.Source.Registry != nil {
@@ -1135,7 +1193,7 @@ func (c *KpmClient) Download(dep *pkg.Dependency, homePath, localPath string) (*
11351193
}
11361194

11371195
// DownloadFromGit will download the dependency from the git repository.
1138-
func (c *KpmClient) DownloadFromGit(dep *pkg.Git, localPath string) (string, error) {
1196+
func (c *KpmClient) DownloadFromGit(dep *downloader.Git, localPath string) (string, error) {
11391197
var msg string
11401198
if len(dep.Tag) != 0 {
11411199
msg = fmt.Sprintf("with tag '%s'", dep.Tag)
@@ -1217,7 +1275,7 @@ func (c *KpmClient) ParseKclModFile(kclPkg *pkg.KclPkg) (map[string]map[string]s
12171275
}
12181276

12191277
// LoadPkgFromOci will download the kcl package from the oci repository and return an `KclPkg`.
1220-
func (c *KpmClient) DownloadPkgFromOci(dep *pkg.Oci, localPath string) (*pkg.KclPkg, error) {
1278+
func (c *KpmClient) DownloadPkgFromOci(dep *downloader.Oci, localPath string) (*pkg.KclPkg, error) {
12211279
ociClient, err := oci.NewOciClient(dep.Reg, dep.Repo, &c.settings)
12221280
if err != nil {
12231281
return nil, err
@@ -1263,7 +1321,7 @@ func (c *KpmClient) DownloadPkgFromOci(dep *pkg.Oci, localPath string) (*pkg.Kcl
12631321

12641322
// DownloadFromOci will download the dependency from the oci repository.
12651323
// Deprecated: Use the DownloadPkgFromOci instead.
1266-
func (c *KpmClient) DownloadFromOci(dep *pkg.Oci, localPath string) (string, error) {
1324+
func (c *KpmClient) DownloadFromOci(dep *downloader.Oci, localPath string) (string, error) {
12671325
ociClient, err := oci.NewOciClient(dep.Reg, dep.Repo, &c.settings)
12681326
if err != nil {
12691327
return "", err

pkg/client/client_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ func TestDownloadOci(t *testing.T) {
6767
depFromOci := pkg.Dependency{
6868
Name: "helloworld",
6969
Version: "0.1.2",
70-
Source: pkg.Source{
71-
Oci: &pkg.Oci{
70+
Source: downloader.Source{
71+
Oci: &downloader.Oci{
7272
Reg: "ghcr.io",
7373
Repo: "kcl-lang/helloworld",
7474
Tag: "0.1.2",
@@ -110,8 +110,8 @@ func TestDownloadLatestOci(t *testing.T) {
110110
depFromOci := pkg.Dependency{
111111
Name: "helloworld",
112112
Version: "",
113-
Source: pkg.Source{
114-
Oci: &pkg.Oci{
113+
Source: downloader.Source{
114+
Oci: &downloader.Oci{
115115
Reg: "ghcr.io",
116116
Repo: "kcl-lang/helloworld",
117117
Tag: "",
@@ -284,8 +284,8 @@ func TestUpdateKclModAndLock(t *testing.T) {
284284
FullName: "test_version",
285285
Version: "test_version",
286286
Sum: "test_sum",
287-
Source: pkg.Source{
288-
Git: &pkg.Git{
287+
Source: downloader.Source{
288+
Git: &downloader.Git{
289289
Url: "test_url",
290290
Tag: "test_tag",
291291
},
@@ -297,8 +297,8 @@ func TestUpdateKclModAndLock(t *testing.T) {
297297
FullName: "test_version",
298298
Version: "test_version",
299299
Sum: "test_sum",
300-
Source: pkg.Source{
301-
Oci: &pkg.Oci{
300+
Source: downloader.Source{
301+
Oci: &downloader.Oci{
302302
Reg: "test_reg",
303303
Repo: "test_repo",
304304
Tag: "test_tag",
@@ -1305,7 +1305,7 @@ func TestLoadPkgFormOci(t *testing.T) {
13051305
assert.Equal(t, err, nil)
13061306
}()
13071307

1308-
kclpkg, err := cli.DownloadPkgFromOci(&pkg.Oci{
1308+
kclpkg, err := cli.DownloadPkgFromOci(&downloader.Oci{
13091309
Reg: tc.Reg,
13101310
Repo: tc.Repo,
13111311
Tag: tc.Tag,
@@ -1455,8 +1455,8 @@ func testAddWithOciDownloader(t *testing.T) {
14551455
dep := pkg.Dependency{
14561456
Name: "helloworld",
14571457
FullName: "helloworld_0.0.3",
1458-
Source: pkg.Source{
1459-
Oci: &pkg.Oci{
1458+
Source: downloader.Source{
1459+
Oci: &downloader.Oci{
14601460
Reg: "ghcr.io",
14611461
Repo: "zong-zhe/helloworld",
14621462
Tag: "0.0.3",

pkg/client/pull.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package client
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"path/filepath"
7+
8+
"kcl-lang.io/kpm/pkg/downloader"
9+
pkg "kcl-lang.io/kpm/pkg/package"
10+
"kcl-lang.io/kpm/pkg/reporter"
11+
)
12+
13+
// The PullOptions struct contains the options for pulling a package from the registry.
14+
type PullOptions struct {
15+
// Source is the source of the package to be pulled.
16+
// Including git, oci, local.
17+
Source *downloader.Source
18+
// LocalPath is the local path to download the package.
19+
LocalPath string
20+
}
21+
22+
type PullOption func(*PullOptions) error
23+
24+
func WithPullSourceUrl(sourceUrl string) PullOption {
25+
return func(opts *PullOptions) error {
26+
source, err := downloader.NewSourceFromStr(sourceUrl)
27+
if err != nil {
28+
return err
29+
}
30+
opts.Source = source
31+
return nil
32+
}
33+
}
34+
35+
func WithPullSource(source *downloader.Source) PullOption {
36+
return func(opts *PullOptions) error {
37+
if source == nil {
38+
return errors.New("source cannot be nil")
39+
}
40+
opts.Source = source
41+
return nil
42+
}
43+
}
44+
45+
func WithLocalPath(path string) PullOption {
46+
return func(opts *PullOptions) error {
47+
opts.LocalPath = path
48+
return nil
49+
}
50+
}
51+
52+
func NewPullOptions(opts ...PullOption) *PullOptions {
53+
do := &PullOptions{}
54+
for _, opt := range opts {
55+
opt(do)
56+
}
57+
return do
58+
}
59+
60+
func (c *KpmClient) Pull(options ...PullOption) (*pkg.KclPkg, error) {
61+
opts := &PullOptions{}
62+
for _, option := range options {
63+
if err := option(opts); err != nil {
64+
return nil, err
65+
}
66+
}
67+
68+
sourceFilePath, err := opts.Source.ToFilePath()
69+
if err != nil {
70+
return nil, err
71+
}
72+
73+
sourceStr, err := opts.Source.ToString()
74+
if err != nil {
75+
return nil, err
76+
}
77+
reporter.ReportMsgTo(
78+
fmt.Sprintf("start to pull %s", sourceStr),
79+
c.GetLogWriter(),
80+
)
81+
82+
kPkg, err := c.downloadPkg(
83+
// The package pulled will be stored in the 'opts.LocalPath/sourceFilePath'
84+
// 'opts.LocalPath' is the local path input by the user.
85+
// 'sourceFilePath' is generated by the source.
86+
// For example,
87+
// kcl package from 'https://github.com/kcl-lang/kcl' will be stored in '$LOCAL_PATH/git/github.com/kcl-lang/kcl'
88+
// kcl package from 'oci://ghcr.io/kcl-lang/kcl' will be stored in '$LOCAL_PATH/oci/ghcr.io/kcl-lang/kcl'
89+
downloader.WithLocalPath(filepath.Join(opts.LocalPath, sourceFilePath)),
90+
downloader.WithSource(*opts.Source),
91+
)
92+
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
reporter.ReportMsgTo(
98+
fmt.Sprintf("pulled %s %s successfully", kPkg.GetPkgName(), kPkg.GetPkgVersion()),
99+
c.GetLogWriter(),
100+
)
101+
return kPkg, nil
102+
}

pkg/client/pull_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package client
2+
3+
import (
4+
"bytes"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"gotest.tools/v3/assert"
10+
"kcl-lang.io/kpm/pkg/downloader"
11+
)
12+
13+
func TestPull(t *testing.T) {
14+
pulledPath := getTestDir("test_pull")
15+
16+
kpmcli, err := NewKpmClient()
17+
assert.NilError(t, err)
18+
19+
var buf bytes.Buffer
20+
kpmcli.SetLogWriter(&buf)
21+
22+
kPkg, err := kpmcli.Pull(
23+
WithLocalPath(pulledPath),
24+
WithPullSource(&downloader.Source{
25+
Oci: &downloader.Oci{
26+
Reg: "ghcr.io",
27+
Repo: "kcl-lang/helloworld",
28+
Tag: "0.0.1",
29+
},
30+
}),
31+
)
32+
33+
pkgPath := filepath.Join(pulledPath, "oci", "ghcr.io", "kcl-lang", "helloworld", "0.0.1")
34+
assert.NilError(t, err)
35+
assert.Equal(t, kPkg.GetPkgName(), "helloworld")
36+
assert.Equal(t, kPkg.GetPkgVersion(), "0.0.1")
37+
assert.Equal(t, kPkg.HomePath, pkgPath)
38+
39+
kPkg, err = kpmcli.Pull(
40+
WithLocalPath(pulledPath),
41+
WithPullSourceUrl("oci://ghcr.io/kcl-lang/helloworld?tag=0.1.0"),
42+
)
43+
pkgPath = filepath.Join(pulledPath, "oci", "ghcr.io", "kcl-lang", "helloworld", "0.1.0")
44+
assert.NilError(t, err)
45+
assert.Equal(t, kPkg.GetPkgName(), "helloworld")
46+
assert.Equal(t, kPkg.GetPkgVersion(), "0.1.0")
47+
assert.Equal(t, kPkg.HomePath, pkgPath)
48+
49+
defer func() {
50+
err = os.RemoveAll(filepath.Join(pulledPath, "oci"))
51+
assert.NilError(t, err)
52+
}()
53+
}

pkg/client/test_data/test_pull/.gitkeep

Whitespace-only changes.

pkg/cmd/cmd_push.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func pushPackage(ociUrl string, kclPkg *pkg.KclPkg, vendorMode bool, kpmcli *cli
180180
)
181181
}
182182

183-
ociOpts.Annotations, err = oci.GenOciManifestFromPkg(kclPkg)
183+
ociOpts.Annotations, err = kclPkg.GenOciManifestFromPkg()
184184
if err != nil {
185185
return err
186186
}

0 commit comments

Comments
 (0)