Skip to content

Commit 4da496e

Browse files
authored
feat: support the upload command and optimize the log (#215)
Signed-off-by: chlins <[email protected]>
1 parent b24b4d3 commit 4da496e

File tree

27 files changed

+462
-122
lines changed

27 files changed

+462
-122
lines changed

cmd/modelfile/modelfile.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
package modelfile
1818

1919
import (
20-
"github.com/sirupsen/logrus"
21-
2220
"github.com/spf13/cobra"
2321
"github.com/spf13/viper"
2422
)
@@ -32,8 +30,6 @@ var RootCmd = &cobra.Command{
3230
SilenceUsage: true,
3331
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
3432
RunE: func(cmd *cobra.Command, args []string) error {
35-
logrus.Debug("modctl modelfile is running")
36-
3733
return nil
3834
},
3935
}

cmd/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,6 @@ func init() {
142142
rootCmd.AddCommand(tagCmd)
143143
rootCmd.AddCommand(fetchCmd)
144144
rootCmd.AddCommand(attachCmd)
145+
rootCmd.AddCommand(uploadCmd)
145146
rootCmd.AddCommand(modelfile.RootCmd)
146147
}

cmd/upload.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2025 The CNAI Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package cmd
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
"github.com/spf13/cobra"
24+
"github.com/spf13/viper"
25+
26+
"github.com/CloudNativeAI/modctl/pkg/backend"
27+
"github.com/CloudNativeAI/modctl/pkg/config"
28+
)
29+
30+
var uploadConfig = config.NewUpload()
31+
32+
// uploadCmd represents the modctl command for upload.
33+
var uploadCmd = &cobra.Command{
34+
Use: "upload [flags] <file>",
35+
Short: "A command line tool for modctl upload",
36+
Args: cobra.ExactArgs(1),
37+
DisableAutoGenTag: true,
38+
SilenceUsage: true,
39+
FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true},
40+
RunE: func(cmd *cobra.Command, args []string) error {
41+
if err := uploadConfig.Validate(); err != nil {
42+
return err
43+
}
44+
45+
return runUpload(context.Background(), args[0])
46+
},
47+
}
48+
49+
// init initializes upload command.
50+
func init() {
51+
flags := uploadCmd.Flags()
52+
flags.StringVarP(&uploadConfig.Repo, "repo", "", "", "target model artifact repository name")
53+
flags.BoolVarP(&uploadConfig.PlainHTTP, "plain-http", "", false, "turning on this flag will use plain HTTP instead of HTTPS")
54+
flags.BoolVarP(&uploadConfig.Insecure, "insecure", "", false, "turning on this flag will disable TLS verification")
55+
flags.BoolVar(&uploadConfig.Raw, "raw", false, "turning on this flag will upload model artifact layer in raw format")
56+
57+
if err := viper.BindPFlags(flags); err != nil {
58+
panic(fmt.Errorf("bind cache list flags to viper: %w", err))
59+
}
60+
}
61+
62+
// runUpload runs the upload modctl.
63+
func runUpload(ctx context.Context, filepath string) error {
64+
b, err := backend.New(rootConfig.StoargeDir)
65+
if err != nil {
66+
return err
67+
}
68+
69+
if err := b.Upload(ctx, filepath, uploadConfig); err != nil {
70+
return err
71+
}
72+
73+
fmt.Printf("Successfully uploaded %s to model artifact repository: %s\n", filepath, uploadConfig.Repo)
74+
return nil
75+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ require (
2424
github.com/vbauerster/mpb/v8 v8.10.2
2525
golang.org/x/crypto v0.39.0
2626
golang.org/x/sync v0.15.0
27+
golang.org/x/sys v0.33.0
2728
google.golang.org/grpc v1.73.0
2829
oras.land/oras-go/v2 v2.6.0
2930
)
@@ -111,7 +112,6 @@ require (
111112
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
112113
go.uber.org/multierr v1.11.0 // indirect
113114
golang.org/x/net v0.41.0 // indirect
114-
golang.org/x/sys v0.33.0 // indirect
115115
golang.org/x/term v0.32.0 // indirect
116116
golang.org/x/text v0.26.0 // indirect
117117
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect

pkg/backend/attach.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ var (
6060

6161
// Attach attaches user materials into the model artifact which follows the Model Spec.
6262
func (b *backend) Attach(ctx context.Context, filepath string, cfg *config.Attach) error {
63-
logrus.Infof("attaching file %s, cfg: %+v", filepath, cfg)
63+
logrus.Infof("attach: starting attach operation for file %s [config: %+v]", filepath, cfg)
6464
srcManifest, err := b.getManifest(ctx, cfg.Source, cfg.OutputRemote, cfg.PlainHTTP, cfg.Insecure)
6565
if err != nil {
6666
return fmt.Errorf("failed to get source manifest: %w", err)
@@ -71,7 +71,7 @@ func (b *backend) Attach(ctx context.Context, filepath string, cfg *config.Attac
7171
return fmt.Errorf("failed to get source model config: %w", err)
7272
}
7373

74-
logrus.Infof("source model config: %+v", srcModelConfig)
74+
logrus.Infof("attach: loaded source model config [%+v]", srcModelConfig)
7575

7676
var foundLayer *ocispec.Descriptor
7777
for _, layer := range srcManifest.Layers {
@@ -87,7 +87,7 @@ func (b *backend) Attach(ctx context.Context, filepath string, cfg *config.Attac
8787
}
8888
}
8989

90-
logrus.Infof("found original layer: %+v", foundLayer)
90+
logrus.Infof("attach: found existing layer for file %s [%+v]", filepath, foundLayer)
9191

9292
layers := srcManifest.Layers
9393
if foundLayer != nil {
@@ -100,7 +100,7 @@ func (b *backend) Attach(ctx context.Context, filepath string, cfg *config.Attac
100100
}
101101
}
102102

103-
proc := b.getProcessor(filepath, cfg)
103+
proc := b.getProcessor(filepath, cfg.Raw)
104104
if proc == nil {
105105
return fmt.Errorf("failed to get processor for file %s", filepath)
106106
}
@@ -123,7 +123,7 @@ func (b *backend) Attach(ctx context.Context, filepath string, cfg *config.Attac
123123
layers = append(layers, newLayers...)
124124
sortLayers(layers)
125125

126-
logrus.Infof("new sorted layers: %+v", layers)
126+
logrus.Debugf("attach: generated sorted layers [layers: %+v]", layers)
127127

128128
diffIDs := []godigest.Digest{}
129129
for _, layer := range layers {
@@ -145,7 +145,7 @@ func (b *backend) Attach(ctx context.Context, filepath string, cfg *config.Attac
145145
Name: srcModelConfig.Descriptor.Name,
146146
}
147147

148-
logrus.Infof("new model config: %+v", modelConfig)
148+
logrus.Infof("attach: built model config [%+v]", modelConfig)
149149

150150
configDesc, err := builder.BuildConfig(ctx, layers, modelConfig, hooks.NewHooks(
151151
hooks.WithOnStart(func(name string, size int64, reader io.Reader) io.Reader {
@@ -178,6 +178,7 @@ func (b *backend) Attach(ctx context.Context, filepath string, cfg *config.Attac
178178
return fmt.Errorf("failed to build model manifest: %w", err)
179179
}
180180

181+
logrus.Infof("attach: successfully attached file %s", filepath)
181182
return nil
182183
}
183184

@@ -272,34 +273,34 @@ func (b *backend) getModelConfig(ctx context.Context, reference string, desc oci
272273
return &model, nil
273274
}
274275

275-
func (b *backend) getProcessor(filepath string, cfg *config.Attach) processor.Processor {
276+
func (b *backend) getProcessor(filepath string, rawMediaType bool) processor.Processor {
276277
if modelfile.IsFileType(filepath, modelfile.ConfigFilePatterns) {
277278
mediaType := modelspec.MediaTypeModelWeightConfig
278-
if cfg.Raw {
279+
if rawMediaType {
279280
mediaType = modelspec.MediaTypeModelWeightConfigRaw
280281
}
281282
return processor.NewModelConfigProcessor(b.store, mediaType, []string{filepath})
282283
}
283284

284285
if modelfile.IsFileType(filepath, modelfile.ModelFilePatterns) {
285286
mediaType := modelspec.MediaTypeModelWeight
286-
if cfg.Raw {
287+
if rawMediaType {
287288
mediaType = modelspec.MediaTypeModelWeightRaw
288289
}
289290
return processor.NewModelProcessor(b.store, mediaType, []string{filepath})
290291
}
291292

292293
if modelfile.IsFileType(filepath, modelfile.CodeFilePatterns) {
293294
mediaType := modelspec.MediaTypeModelCode
294-
if cfg.Raw {
295+
if rawMediaType {
295296
mediaType = modelspec.MediaTypeModelCodeRaw
296297
}
297298
return processor.NewCodeProcessor(b.store, mediaType, []string{filepath})
298299
}
299300

300301
if modelfile.IsFileType(filepath, modelfile.DocFilePatterns) {
301302
mediaType := modelspec.MediaTypeModelDoc
302-
if cfg.Raw {
303+
if rawMediaType {
303304
mediaType = modelspec.MediaTypeModelDocRaw
304305
}
305306
return processor.NewDocProcessor(b.store, mediaType, []string{filepath})

pkg/backend/attach_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestGetProcessor(t *testing.T) {
7373

7474
for _, tt := range tests {
7575
t.Run(tt.filepath, func(t *testing.T) {
76-
proc := b.getProcessor(tt.filepath, &config.Attach{})
76+
proc := b.getProcessor(tt.filepath, false)
7777
if tt.wantType == "" {
7878
assert.Nil(t, proc)
7979
} else {

pkg/backend/backend.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ type Backend interface {
3434
// Attach attaches user materials into the model artifact which follows the Model Spec.
3535
Attach(ctx context.Context, filepath string, cfg *config.Attach) error
3636

37+
// Upload uploads the file to a model artifact repository in advance, but will not push config and manifest.
38+
Upload(ctx context.Context, filepath string, cfg *config.Upload) error
39+
3740
// Build builds the user materials into the model artifact which follows the Model Spec.
3841
Build(ctx context.Context, modelfilePath, workDir, target string, cfg *config.Build) error
3942

pkg/backend/build.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const (
4646

4747
// Build builds the user materials into the model artifact which follows the Model Spec.
4848
func (b *backend) Build(ctx context.Context, modelfilePath, workDir, target string, cfg *config.Build) error {
49-
logrus.Infof("building model artifact: %s, cfg: %+v", target, cfg)
49+
logrus.Infof("build: starting build operation for target %s [config: %+v]", target, cfg)
5050
// parse the repo name and tag name from target.
5151
ref, err := ParseReference(target)
5252
if err != nil {
@@ -99,7 +99,7 @@ func (b *backend) Build(ctx context.Context, modelfilePath, workDir, target stri
9999

100100
layers = append(layers, layerDescs...)
101101

102-
logrus.Infof("model artifact layers: %+v", layers)
102+
logrus.Infof("build: processed layers for artifact [count: %d, layers: %+v]", len(layers), layers)
103103

104104
revision := sourceInfo.Commit
105105
if revision != "" && sourceInfo.Dirty {
@@ -118,7 +118,7 @@ func (b *backend) Build(ctx context.Context, modelfilePath, workDir, target stri
118118
SourceRevision: revision,
119119
}
120120

121-
logrus.Infof("model artifact config: %+v", modelConfig)
121+
logrus.Infof("build: built model config [family: %s, name: %s, format: %s]", modelConfig.Family, modelConfig.Name, modelConfig.Format)
122122

123123
var configDesc ocispec.Descriptor
124124
// Build the model config.
@@ -157,6 +157,7 @@ func (b *backend) Build(ctx context.Context, modelfilePath, workDir, target stri
157157
return fmt.Errorf("failed to build model manifest: %w", err)
158158
}
159159

160+
logrus.Infof("build: successfully built model artifact %s", target)
160161
return nil
161162
}
162163

0 commit comments

Comments
 (0)