@@ -23,9 +23,12 @@ import (
2323 "io"
2424 "net/http"
2525 "net/url"
26+ "path/filepath"
2627
28+ "github.com/CloudNativeAI/modctl/pkg/archiver"
2729 "github.com/CloudNativeAI/modctl/pkg/storage"
2830
31+ modelspec "github.com/CloudNativeAI/model-spec/specs-go/v1"
2932 ocispec "github.com/opencontainers/image-spec/specs-go/v1"
3033 "oras.land/oras-go/v2/registry/remote"
3134 "oras.land/oras-go/v2/registry/remote/auth"
@@ -124,6 +127,13 @@ func (b *backend) Pull(ctx context.Context, target string, opts ...Option) error
124127 return fmt .Errorf ("failed to pull manifest to local: %w" , err )
125128 }
126129
130+ // export the target model artifact to the output directory if needed.
131+ if options .outputPath != "" {
132+ if err := exportModelArtifact (ctx , dst , manifest , repo , options .outputPath ); err != nil {
133+ return fmt .Errorf ("failed to export the artifact to the output directory: %w" , err )
134+ }
135+ }
136+
127137 return nil
128138}
129139
@@ -162,3 +172,30 @@ func pullIfNotExist(ctx context.Context, pb *ProgressBar, prompt string, src *re
162172
163173 return nil
164174}
175+
176+ // exportModelArtifact exports the target model artifact to the output directory, which will open the artifact and extract to restore the orginal repo structure.
177+ func exportModelArtifact (ctx context.Context , store storage.Storage , manifest ocispec.Manifest , repo , outputPath string ) error {
178+ for _ , layer := range manifest .Layers {
179+ // pull the blob from the storage.
180+ reader , err := store .PullBlob (ctx , repo , layer .Digest .String ())
181+ if err != nil {
182+ return fmt .Errorf ("failed to pull the blob from storage: %w" , err )
183+ }
184+
185+ defer reader .Close ()
186+
187+ targetPath := outputPath
188+ // get the original filepath in order to restore the original repo structure.
189+ originalFilePath := layer .Annotations [modelspec .AnnotationFilepath ]
190+ if dir := filepath .Dir (originalFilePath ); dir != "" {
191+ targetPath = filepath .Join (targetPath , dir )
192+ }
193+
194+ // untar the blob to the output directory.
195+ if err := archiver .Untar (reader , targetPath ); err != nil {
196+ return fmt .Errorf ("failed to untar the blob to output directory: %w" , err )
197+ }
198+ }
199+
200+ return nil
201+ }
0 commit comments