@@ -26,8 +26,8 @@ import (
2626 "path/filepath"
2727 "time"
2828
29- "github.com/CloudNativeAI/modctl/pkg/archiver"
3029 "github.com/CloudNativeAI/modctl/pkg/backend/build/hooks"
30+ "github.com/CloudNativeAI/modctl/pkg/codec"
3131 "github.com/CloudNativeAI/modctl/pkg/modelfile"
3232 "github.com/CloudNativeAI/modctl/pkg/storage"
3333
@@ -38,11 +38,6 @@ import (
3838 ocispec "github.com/opencontainers/image-spec/specs-go/v1"
3939)
4040
41- // tarHeaderSize is the size of a tar header.
42- // TODO: the real size should be calculated based on the actual stream,
43- // now we use a fixed size in order to avoid extra read costs.
44- const tarHeaderSize = 512
45-
4641// OutputType defines the type of output to generate.
4742type OutputType string
4843
@@ -67,7 +62,7 @@ type Builder interface {
6762
6863type OutputStrategy interface {
6964 // OutputLayer outputs the layer blob to the storage (local or remote).
70- OutputLayer (ctx context.Context , mediaType , workDir , relPath string , size int64 , reader io.Reader , hooks hooks.Hooks ) (ocispec.Descriptor , error )
65+ OutputLayer (ctx context.Context , mediaType , relPath , digest string , size int64 , reader io.Reader , hooks hooks.Hooks ) (ocispec.Descriptor , error )
7166
7267 // OutputConfig outputs the config blob to the storage (local or remote).
7368 OutputConfig (ctx context.Context , mediaType , digest string , size int64 , reader io.Reader , hooks hooks.Hooks ) (ocispec.Descriptor , error )
@@ -141,12 +136,40 @@ func (ab *abstractBuilder) BuildLayer(ctx context.Context, mediaType, workDir, p
141136 return ocispec.Descriptor {}, fmt .Errorf ("failed to get relative path: %w" , err )
142137 }
143138
144- reader , err := archiver .Tar (path , workDirPath )
139+ codec , err := codec .New (codec .TypeFromMediaType (mediaType ))
140+ if err != nil {
141+ return ocispec.Descriptor {}, fmt .Errorf ("failed to create codec: %w" , err )
142+ }
143+
144+ // Encode the content by codec depends on the media type.
145+ reader , err := codec .Encode (path , workDirPath )
146+ if err != nil {
147+ return ocispec.Descriptor {}, fmt .Errorf ("failed to encode file: %w" , err )
148+ }
149+
150+ // Calculate the digest of the encoded content.
151+ hash := sha256 .New ()
152+ size , err := io .Copy (hash , reader )
145153 if err != nil {
146- return ocispec.Descriptor {}, fmt .Errorf ("failed to tar file: %w" , err )
154+ return ocispec.Descriptor {}, fmt .Errorf ("failed to copy content to hash: %w" , err )
155+ }
156+
157+ digest := fmt .Sprintf ("sha256:%x" , hash .Sum (nil ))
158+
159+ // Seek the reader to the beginning if supported,
160+ // otherwise we needs to re-encode the content again.
161+ if seeker , ok := reader .(io.ReadSeeker ); ok {
162+ if _ , err := seeker .Seek (0 , io .SeekStart ); err != nil {
163+ return ocispec.Descriptor {}, fmt .Errorf ("failed to seek reader: %w" , err )
164+ }
165+ } else {
166+ reader , err = codec .Encode (path , workDirPath )
167+ if err != nil {
168+ return ocispec.Descriptor {}, fmt .Errorf ("failed to encode file: %w" , err )
169+ }
147170 }
148171
149- return ab .strategy .OutputLayer (ctx , mediaType , workDir , relPath , info . Size () + tarHeaderSize , reader , hooks )
172+ return ab .strategy .OutputLayer (ctx , mediaType , relPath , digest , size , reader , hooks )
150173}
151174
152175func (ab * abstractBuilder ) BuildConfig (ctx context.Context , layers []ocispec.Descriptor , hooks hooks.Hooks ) (ocispec.Descriptor , error ) {
0 commit comments