Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/convertor/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func (b *graphBuilder) process(ctx context.Context, src v1.Descriptor, tag bool)
var wg sync.WaitGroup
var mu sync.Mutex
var filteredManifests []v1.Descriptor

for _, m := range index.Manifests {
manifest := m
wg.Add(1)
Expand All @@ -187,7 +187,7 @@ func (b *graphBuilder) process(ctx context.Context, src v1.Descriptor, tag bool)
if ctx.Err() != nil {
return v1.Descriptor{}, ctx.Err()
}

// Update index with only the non-provenance manifests
index.Manifests = filteredManifests

Expand Down Expand Up @@ -328,7 +328,7 @@ func (b *graphBuilder) buildOne(ctx context.Context, src v1.Descriptor, tag bool

func Build(ctx context.Context, opt BuilderOptions) error {
var resolver remotes.Resolver

// Use custom resolver if provided, otherwise create default docker resolver
if opt.CustomResolver != nil {
log.G(ctx).Info("using custom resolver (tar import mode)")
Expand Down
2 changes: 1 addition & 1 deletion cmd/convertor/builder/builder_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func Test_fetchManifest(t *testing.T) {
// 2. Manifest lists (which require platform-specific manifest selection)
if tt.args.desc.MediaType != images.MediaTypeDockerSchema2ManifestList &&
tt.args.desc.MediaType != v1.MediaTypeImageIndex {

// For regular manifests, we can directly compare the digest
// because we expect to get back exactly what we asked for
if tt.args.desc.Digest != contentDigest {
Expand Down
24 changes: 12 additions & 12 deletions cmd/convertor/builder/content_store_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func NewContentStoreResolverFromTar(ctx context.Context, tarPath string) (*Conte
}
defer tarFile.Close()

// Import tar into content store
// Import tar into content store
log.G(ctx).Infof("importing tar file: %s", tarPath)
indexDesc, err := archive.ImportIndex(ctx, store, tarFile,
archive.WithImportCompression(),
Expand All @@ -119,18 +119,18 @@ func NewContentStoreResolverFromTar(ctx context.Context, tarPath string) (*Conte
log.G(ctx).Infof(" MediaType: %s", manifest.MediaType)
log.G(ctx).Infof(" Digest: %s", manifest.Digest)
log.G(ctx).Infof(" Size: %d bytes", manifest.Size)

if manifest.Platform != nil {
log.G(ctx).Infof(" Platform: %s/%s", manifest.Platform.OS, manifest.Platform.Architecture)
if manifest.Platform.Variant != "" {
log.G(ctx).Infof(" Platform Variant: %s", manifest.Platform.Variant)
}
}

if manifest.ArtifactType != "" {
log.G(ctx).Infof(" ArtifactType: %s", manifest.ArtifactType)
}

if manifest.Annotations != nil && len(manifest.Annotations) > 0 {
log.G(ctx).Infof(" Annotations:")
for key, value := range manifest.Annotations {
Expand All @@ -144,10 +144,10 @@ func NewContentStoreResolverFromTar(ctx context.Context, tarPath string) (*Conte
continue
}

// Check if this is an image index (multi-arch)
// Check if this is an image index (multi-arch)
if manifest.MediaType == v1.MediaTypeImageIndex || manifest.MediaType == "application/vnd.docker.distribution.manifest.list.v2+json" {
log.G(ctx).Infof(" 📁 FOUND IMAGE INDEX: Importing as-is for multi-arch conversion")

// Import the index itself - let the builder handle platform traversal
ref := fmt.Sprintf("imported:%s", manifest.Digest.Encoded()[:12])
if manifest.Annotations != nil {
Expand Down Expand Up @@ -194,7 +194,7 @@ func (r *ContentStoreResolver) Resolve(ctx context.Context, ref string) (string,

// Parse reference
name, tag := parseRef(ref)

// Look up in image store
image, err := r.imageStore.Get(ctx, name)
if err != nil {
Expand Down Expand Up @@ -455,7 +455,7 @@ func isProvenanceManifest(desc v1.Descriptor) bool {
// by examining both the descriptor metadata and the actual manifest content
func isProvenanceManifestWithContent(ctx context.Context, store content.Store, desc v1.Descriptor) bool {
log.G(ctx).Debugf(" 🔍 Checking if manifest is provenance: %s", desc.Digest)

// First check descriptor metadata
if isProvenanceManifest(desc) {
log.G(ctx).Debugf(" 🔍 Detected provenance via descriptor metadata")
Expand All @@ -465,9 +465,9 @@ func isProvenanceManifestWithContent(ctx context.Context, store content.Store, d
// For generic manifest media types, we need to check the content
if desc.MediaType == "application/vnd.docker.distribution.manifest.v2+json" ||
desc.MediaType == "application/vnd.oci.image.manifest.v1+json" {

log.G(ctx).Debugf(" 🔍 Generic manifest media type, reading content to inspect...")

// Read the manifest content
manifestContent, err := content.ReadBlob(ctx, store, desc)
if err != nil {
Expand All @@ -492,11 +492,11 @@ func isProvenanceManifestWithContent(ctx context.Context, store content.Store, d
log.G(ctx).Debugf(" 🔍 FOUND provenance markers in content!")
return true
}

log.G(ctx).Debugf(" 🔍 No provenance markers found in content")
} else {
log.G(ctx).Debugf(" 🔍 Non-generic media type, skipping content inspection")
}

return false
}
}
24 changes: 12 additions & 12 deletions cmd/convertor/builder/file_pusher.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ import (
// FileBasedResolver implements remotes.Resolver that captures pushed content locally
// for later export to tar files
type FileBasedResolver struct {
store content.Store
imageStore images.Store
outputStore content.Store // Where converted layers are stored
store content.Store
imageStore images.Store
outputStore content.Store // Where converted layers are stored
outputImageStore images.Store
tempDir string // Path to temporary directory for cleanup
tempDir string // Path to temporary directory for cleanup
}

// NewFileBasedResolver creates a resolver that captures converted content locally
Expand Down Expand Up @@ -94,7 +94,7 @@ func (r *FileBasedResolver) OutputImageStore() images.Store {
// Resolve resolves a reference from the import store
func (r *FileBasedResolver) Resolve(ctx context.Context, ref string) (string, v1.Descriptor, error) {
log.G(ctx).Debugf("file-based resolver: resolving reference: %s", ref)

// Look up in import image store
image, err := r.imageStore.Get(ctx, ref)
if err != nil {
Expand All @@ -114,7 +114,7 @@ func (r *FileBasedResolver) Fetcher(ctx context.Context, ref string) (remotes.Fe
// Pusher returns a file-based pusher that captures converted content locally
func (r *FileBasedResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) {
log.G(ctx).Debugf("file-based resolver: creating pusher for ref: %s", ref)

return &FilePusher{
ref: ref,
store: r.outputStore,
Expand Down Expand Up @@ -167,7 +167,7 @@ type fileWriter struct {

func (w *fileWriter) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
log.G(ctx).Debugf("file pusher: committing blob: %s", w.desc.Digest)

err := w.Writer.Commit(ctx, size, expected, opts...)
if err != nil {
return err
Expand All @@ -176,7 +176,7 @@ func (w *fileWriter) Commit(ctx context.Context, size int64, expected digest.Dig
// If this is a manifest, store it in the image store as well
if isManifestMediaType(w.desc.MediaType) {
log.G(ctx).Debugf("file pusher: storing manifest in image store: %s", w.desc.Digest)

// Generate image name based on the pusher's reference
imageName := fmt.Sprintf("converted:%s", w.desc.Digest.Encoded()[:12])
if w.pusher.ref != "" {
Expand All @@ -195,7 +195,7 @@ func (w *fileWriter) Commit(ctx context.Context, size int64, expected digest.Dig
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}

_, err = w.pusher.imageStore.Create(ctx, image)
if err != nil && !errdefs.IsAlreadyExists(err) {
log.G(ctx).Warnf("failed to store image in image store: %v", err)
Expand All @@ -215,7 +215,7 @@ func isManifestMediaType(mediaType string) bool {
v1.MediaTypeImageIndex,
"application/vnd.docker.distribution.manifest.list.v2+json",
}

for _, mt := range manifestTypes {
if mediaType == mt {
return true
Expand All @@ -233,7 +233,7 @@ func (r *FileBasedResolver) CleanupTempDir() error {
return nil
}

// GetTempDir returns the temporary directory path for debugging
// GetTempDir returns the temporary directory path for debugging
func (r *FileBasedResolver) GetTempDir() string {
return r.tempDir
}
}
71 changes: 71 additions & 0 deletions cmd/convertor/builder/registry_export_resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
Copyright The Accelerated Container Image Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package builder

import (
"context"

"github.com/containerd/containerd/v2/core/content"
"github.com/containerd/containerd/v2/core/images"
"github.com/containerd/containerd/v2/core/remotes"
"github.com/containerd/log"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)

// RegistryExportResolver implements remotes.Resolver that:
// - Fetches from import content store (tar)
// - Pushes to registry using a registry resolver
type RegistryExportResolver struct {
store content.Store
imageStore images.Store
registryResolver remotes.Resolver // For creating registry pushers
}

// NewRegistryExportResolver creates a resolver for tar import -> registry export
func NewRegistryExportResolver(importStore content.Store, importImageStore images.Store, registryResolver remotes.Resolver) *RegistryExportResolver {
return &RegistryExportResolver{
store: importStore,
imageStore: importImageStore,
registryResolver: registryResolver,
}
}

// Resolve resolves a reference from the import store
func (r *RegistryExportResolver) Resolve(ctx context.Context, ref string) (string, v1.Descriptor, error) {
log.G(ctx).Debugf("registry export resolver: resolving reference: %s", ref)

// Look up in import image store
image, err := r.imageStore.Get(ctx, ref)
if err != nil {
return "", v1.Descriptor{}, err
}

return ref, image.Target, nil
}

// Fetcher returns a fetcher for the import content store
func (r *RegistryExportResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
return &ContentStoreFetcher{
store: r.store,
}, nil
}

// Pusher returns a registry pusher from the registry resolver
func (r *RegistryExportResolver) Pusher(ctx context.Context, ref string) (remotes.Pusher, error) {
log.G(ctx).Debugf("registry export resolver: creating registry pusher for ref: %s", ref)
return r.registryResolver.Pusher(ctx, ref)
}
Loading
Loading