Skip to content

Commit

Permalink
move pkg/crane.Rebase into cmd/crane/cmd/rebase.go for now
Browse files Browse the repository at this point in the history
  • Loading branch information
imjasonh committed Aug 4, 2021
1 parent 25b644f commit 0b0fec4
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 113 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
bazel*
.idea
*.iml

crane
gcrane
127 changes: 117 additions & 10 deletions cmd/crane/cmd/rebase.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
package cmd

import (
"errors"
"fmt"
"log"

"github.com/google/go-cmp/cmp"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/logs"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/remote"
specsv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/cobra"
)

Expand All @@ -40,21 +44,49 @@ func NewCmdRebase(options *[]crane.Option) *cobra.Command {
return fmt.Errorf("cannot use --original with positional argument")
}

// Parse and fetch the original image.
// Parse and fetch the original image or index.
origRef, err := name.ParseReference(orig)
if err != nil {
return fmt.Errorf("parsing tag %q: %v", orig, err)
}
origImg, err := remote.Image(origRef)
origDesc, err := remote.Get(origRef)
if err != nil {
return err
}
origDigest, err := origImg.Digest()
if origDesc.Descriptor.MediaType.IsIndex() {
return errors.New("rebasing indexes is not currently supported")
}

// TODO: This will bias toward rebasing the linux/amd64
// image, instead of the whole index. Support rebasing
// indexes, and support the --platform flag here.
origImg, err := origDesc.Image()
if err != nil {
return err
}

rebasedImg, err := crane.Rebase(origImg, oldBase, newBase, *options...)
anns := origDesc.Descriptor.Annotations
if newBase == "" {
if anns != nil && anns[specsv1.AnnotationBaseImageName] != "" {
newBase = anns[specsv1.AnnotationBaseImageName]
} else {
return errors.New("could not determine new base image from annotations")
}
}
newBaseRef, err := name.ParseReference(newBase)
if err != nil {
return err
}
if oldBase == "" {
if anns != nil && anns[specsv1.AnnotationBaseImageName] != "" {
oldBaseDigest := anns[specsv1.AnnotationBaseImageDigest]
oldBase = newBaseRef.Context().Digest(oldBaseDigest).String()
} else {
return errors.New("could not determine old base image by digest from annotations")
}
}

rebasedImg, err := rebaseImage(origImg, oldBase, newBase, *options...)
if err != nil {
return fmt.Errorf("rebasing image: %v", err)
}
Expand All @@ -70,20 +102,24 @@ func NewCmdRebase(options *[]crane.Option) *cobra.Command {
rebased = orig
}
}
log.Println("pushing rebased image as", rebased)
logs.Progress.Println("pushing rebased image as", rebased)
rebasedDigest, err := rebasedImg.Digest()
if err != nil {
return fmt.Errorf("digesting new image: %v", err)
}
origDigest, err := origImg.Digest()
if err != nil {
return err
}
if rebasedDigest == origDigest {
log.Println("INFO: rebased was no-op")
logs.Warn.Println("rebasing was no-op")
} else {
log.Println("rebased digest: ", rebasedDigest)
log.Println("original digest:", origDigest)
logs.Debug.Println("rebased digest: ", rebasedDigest)
logs.Debug.Println("original digest:", origDigest)

origManifest, _ := origImg.Manifest()
rebasedManifest, _ := rebasedImg.Manifest()
log.Println("DIFF:", cmp.Diff(origManifest, rebasedManifest))
logs.Debug.Println("DIFF:", cmp.Diff(origManifest, rebasedManifest))
}

r, err := name.ParseReference(rebased)
Expand Down Expand Up @@ -116,3 +152,74 @@ func NewCmdRebase(options *[]crane.Option) *cobra.Command {
rebaseCmd.Flags().StringVarP(&rebased, "tag", "t", "", "Tag to apply to rebased image")
return rebaseCmd
}

// rebaseImage parses the references and uses them to perform a rebase on the
// original image.
//
// If oldBase or newBase are "", rebaseImage attempts to derive them using
// annotations in the original image. If those annotations are not found,
// rebaseImage returns an error.
//
// If rebasing is successful, base image annotations are set on the resulting
// image to facilitate implicit rebasing next time.
func rebaseImage(orig v1.Image, oldBase, newBase string, opt ...crane.Option) (v1.Image, error) {
m, err := orig.Manifest()
if err != nil {
return nil, err
}
if newBase == "" && m.Annotations != nil {
newBase = m.Annotations[specsv1.AnnotationBaseImageName]
if newBase != "" {
logs.Debug.Printf("Detected new base from %q annotation: %s", specsv1.AnnotationBaseImageName, newBase)
}
}
if newBase == "" {
return nil, fmt.Errorf("either new base or %q annotation is required", specsv1.AnnotationBaseImageName)
}
newBaseImg, err := crane.Pull(newBase, opt...)
if err != nil {
return nil, err
}

if oldBase == "" && m.Annotations != nil {
oldBase = m.Annotations[specsv1.AnnotationBaseImageDigest]
if oldBase != "" {
newBaseRef, err := name.ParseReference(newBase)
if err != nil {
return nil, err
}

oldBase = newBaseRef.Context().Digest(oldBase).String()
logs.Debug.Printf("Detected old base from %q annotation: %s", specsv1.AnnotationBaseImageDigest, oldBase)
}
}
if oldBase == "" {
return nil, fmt.Errorf("either old base or %q annotation is required", specsv1.AnnotationBaseImageDigest)
}

oldBaseImg, err := crane.Pull(oldBase, opt...)
if err != nil {
return nil, err
}

// NB: if newBase is an index, we need to grab the index's digest to
// annotate the resulting image, even though we pull the
// platform-specific image to rebase.
newBaseDigest, err := crane.Digest(newBase, opt...)
if err != nil {
return nil, err
}

rebased, err := mutate.Rebase(orig, oldBaseImg, newBaseImg)
if err != nil {
return nil, err
}

// Update base image annotations for the new image manifest.
logs.Debug.Printf("Setting annotation %q: %q", specsv1.AnnotationBaseImageDigest, newBaseDigest)
logs.Debug.Printf("Setting annotation %q: %q", specsv1.AnnotationBaseImageName, newBase)
return mutate.Annotations(rebased, map[string]string{
specsv1.AnnotationBaseImageDigest: newBaseDigest,
specsv1.AnnotationBaseImageName: newBase,
}).(v1.Image), nil
}
103 changes: 0 additions & 103 deletions pkg/crane/rebase.go

This file was deleted.

0 comments on commit 0b0fec4

Please sign in to comment.