@@ -26,8 +26,8 @@ import (
26
26
"path/filepath"
27
27
"time"
28
28
29
- "github.com/CloudNativeAI/modctl/pkg/archiver"
30
29
"github.com/CloudNativeAI/modctl/pkg/backend/build/hooks"
30
+ "github.com/CloudNativeAI/modctl/pkg/codec"
31
31
"github.com/CloudNativeAI/modctl/pkg/modelfile"
32
32
"github.com/CloudNativeAI/modctl/pkg/storage"
33
33
@@ -38,11 +38,6 @@ import (
38
38
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
39
39
)
40
40
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
-
46
41
// OutputType defines the type of output to generate.
47
42
type OutputType string
48
43
@@ -67,7 +62,7 @@ type Builder interface {
67
62
68
63
type OutputStrategy interface {
69
64
// 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 )
71
66
72
67
// OutputConfig outputs the config blob to the storage (local or remote).
73
68
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
141
136
return ocispec.Descriptor {}, fmt .Errorf ("failed to get relative path: %w" , err )
142
137
}
143
138
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 )
145
153
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
+ }
147
170
}
148
171
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 )
150
173
}
151
174
152
175
func (ab * abstractBuilder ) BuildConfig (ctx context.Context , layers []ocispec.Descriptor , hooks hooks.Hooks ) (ocispec.Descriptor , error ) {
0 commit comments