|
|
@@ -13,9 +13,10 @@ import (
|
|
|
"github.com/docker-library/go-dockerlibrary/manifest"
|
|
|
)
|
|
|
|
|
|
-func entriesToManifestToolYaml(singleArch bool, r Repo, entries ...*manifest.Manifest2822Entry) (string, time.Time, error) {
|
|
|
+func entriesToManifestToolYaml(singleArch bool, r Repo, entries ...*manifest.Manifest2822Entry) (string, time.Time, int, error) {
|
|
|
yaml := ""
|
|
|
mru := time.Time{}
|
|
|
+ expectedNumber := 0
|
|
|
entryIdentifiers := []string{}
|
|
|
for _, entry := range entries {
|
|
|
entryIdentifiers = append(entryIdentifiers, r.EntryIdentifier(*entry))
|
|
|
@@ -45,6 +46,14 @@ func entriesToManifestToolYaml(singleArch bool, r Repo, entries ...*manifest.Man
|
|
|
mru = archU
|
|
|
}
|
|
|
|
|
|
+ // count up how many images we expect to push successfully in this manifest list
|
|
|
+ expectedNumber += len(archImageMeta.Images)
|
|
|
+ // for non-manifest-list tags, this will be 1 and for failed lookups it'll be 0
|
|
|
+ // (and if one of _these_ tags is a manifest list, we've goofed somewhere)
|
|
|
+ if len(archImageMeta.Images) != 1 {
|
|
|
+ fmt.Fprintf(os.Stderr, "warning: expected 1 image for %q; got %d\n", archImage, len(archImageMeta.Images))
|
|
|
+ }
|
|
|
+
|
|
|
yaml += fmt.Sprintf(" - image: %s\n platform:\n", archImage)
|
|
|
yaml += fmt.Sprintf(" os: %s\n", ociArch.OS)
|
|
|
yaml += fmt.Sprintf(" architecture: %s\n", ociArch.Architecture)
|
|
|
@@ -54,7 +63,7 @@ func entriesToManifestToolYaml(singleArch bool, r Repo, entries ...*manifest.Man
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return "manifests:\n" + yaml, mru, nil
|
|
|
+ return "manifests:\n" + yaml, mru, expectedNumber, nil
|
|
|
}
|
|
|
|
|
|
func tagsToManifestToolYaml(repo string, tags ...string) string {
|
|
|
@@ -76,6 +85,7 @@ func cmdPutShared(c *cli.Context) error {
|
|
|
|
|
|
namespace := c.String("namespace")
|
|
|
dryRun := c.Bool("dry-run")
|
|
|
+ force := c.Bool("force")
|
|
|
singleArch := c.Bool("single-arch")
|
|
|
|
|
|
if namespace == "" {
|
|
|
@@ -117,23 +127,41 @@ func cmdPutShared(c *cli.Context) error {
|
|
|
|
|
|
failed := []string{}
|
|
|
for _, group := range sharedTagGroups {
|
|
|
- yaml, mostRecentPush, err := entriesToManifestToolYaml(singleArch, *r, group.Entries...)
|
|
|
+ yaml, mostRecentPush, expectedNumber, err := entriesToManifestToolYaml(singleArch, *r, group.Entries...)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
+ if expectedNumber < 1 {
|
|
|
+ // if "expectedNumber" comes back as 0, we've probably got an API issue, so let's count up what we probably _should_ push
|
|
|
+ fmt.Fprintf(os.Stderr, "warning: no images expected to push for %q\n", fmt.Sprintf("%s:%s", targetRepo, group.SharedTags[0]))
|
|
|
+ for _, entry := range group.Entries {
|
|
|
+ expectedNumber += len(entry.Architectures)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
tagsToPush := []string{}
|
|
|
for _, tag := range group.SharedTags {
|
|
|
image := fmt.Sprintf("%s:%s", targetRepo, tag)
|
|
|
- hubMeta := fetchDockerHubTagMeta(image)
|
|
|
- tagUpdated := hubMeta.lastUpdatedTime()
|
|
|
- if mostRecentPush.After(tagUpdated) ||
|
|
|
- (!singleArch && len(hubMeta.Images) <= 1 &&
|
|
|
- (len(group.Entries) > 1 || len(group.Entries[0].Architectures) > 1)) {
|
|
|
- tagsToPush = append(tagsToPush, tag)
|
|
|
- } else {
|
|
|
- fmt.Fprintf(os.Stderr, "skipping %s (created %s, last updated %s)\n", image, mostRecentPush.Local().Format(time.RFC3339), tagUpdated.Local().Format(time.RFC3339))
|
|
|
+ if !force {
|
|
|
+ hubMeta := fetchDockerHubTagMeta(image)
|
|
|
+ tagUpdated := hubMeta.lastUpdatedTime()
|
|
|
+ doPush := false
|
|
|
+ if mostRecentPush.After(tagUpdated) {
|
|
|
+ // if one of the images that make up the manifest list has been updated since the manifest list was last pushed, we probably need to push
|
|
|
+ doPush = true
|
|
|
+ }
|
|
|
+ if !singleArch && len(hubMeta.Images) != expectedNumber {
|
|
|
+ // if we're supposed to push more (or less) images than the current manifest list contains, we probably need to push
|
|
|
+ // this _should_ already be accounting for tags that haven't been pushed yet (see notes above in "entriesToManifestToolYaml" where this is calculated)
|
|
|
+ doPush = true
|
|
|
+ }
|
|
|
+ if !doPush {
|
|
|
+ fmt.Fprintf(os.Stderr, "skipping %s (created %s, last updated %s)\n", image, mostRecentPush.Local().Format(time.RFC3339), tagUpdated.Local().Format(time.RFC3339))
|
|
|
+ continue
|
|
|
+ }
|
|
|
}
|
|
|
+ tagsToPush = append(tagsToPush, tag)
|
|
|
}
|
|
|
|
|
|
if len(tagsToPush) == 0 {
|