@@ -54,6 +54,7 @@ import (
5454 "path/filepath"
5555 "regexp"
5656 "runtime"
57+ "strconv"
5758 "strings"
5859 "time"
5960
@@ -495,14 +496,45 @@ func doDocker(cmdline []string) {
495496 }
496497 // If architecture specific image builds are requested, build and push them
497498 if * image {
498- build .MustRunCommand ("docker" , "build" , "--tag" , fmt .Sprintf ("%s:TAG" , * upload ), "." )
499- build .MustRunCommand ("docker" , "build" , "--tag" , fmt .Sprintf ("%s:alltools-TAG" , * upload ), "-f" , "Dockerfile.alltools" , "." )
499+ build .MustRunCommand ("docker" , "build" , "--build-arg" , "COMMIT=" + env . Commit , "--build-arg" , "VERSION=" + params . VersionWithMeta , "--build-arg" , "BUILDNUM=" + env . Buildnum , "-- tag" , fmt .Sprintf ("%s:TAG" , * upload ), "." )
500+ build .MustRunCommand ("docker" , "build" , "--build-arg" , "COMMIT=" + env . Commit , "--build-arg" , "VERSION=" + params . VersionWithMeta , "--build-arg" , "BUILDNUM=" + env . Buildnum , "-- tag" , fmt .Sprintf ("%s:alltools-TAG" , * upload ), "-f" , "Dockerfile.alltools" , "." )
500501
501502 // Tag and upload the images to Docker Hub
502503 for _ , tag := range tags {
503504 gethImage := fmt .Sprintf ("%s:%s-%s" , * upload , tag , runtime .GOARCH )
504505 toolImage := fmt .Sprintf ("%s:alltools-%s-%s" , * upload , tag , runtime .GOARCH )
505506
507+ // If the image already exists (non version tag), check the build
508+ // number to prevent overwriting a newer commit if concurrent builds
509+ // are running. This is still a tiny bit racey if two published are
510+ // done at the same time, but that's extremely unlikely even on the
511+ // master branch.
512+ for _ , img := range []string {gethImage , toolImage } {
513+ if exec .Command ("docker" , "pull" , img ).Run () != nil {
514+ continue // Generally the only failure is a missing image, which is good
515+ }
516+ buildnum , err := exec .Command ("docker" , "inspect" , "--format" , "{{index .Config.Labels \" buildnum\" }}" , img ).CombinedOutput ()
517+ if err != nil {
518+ log .Fatalf ("Failed to inspect container: %v\n Output: %s" , err , string (buildnum ))
519+ }
520+ buildnum = bytes .TrimSpace (buildnum )
521+
522+ if len (buildnum ) > 0 && len (env .Buildnum ) > 0 {
523+ oldnum , err := strconv .Atoi (string (buildnum ))
524+ if err != nil {
525+ log .Fatalf ("Failed to parse old image build number: %v" , err )
526+ }
527+ newnum , err := strconv .Atoi (env .Buildnum )
528+ if err != nil {
529+ log .Fatalf ("Failed to parse current build number: %v" , err )
530+ }
531+ if oldnum > newnum {
532+ log .Fatalf ("Current build number %d not newer than existing %d" , newnum , oldnum )
533+ } else {
534+ log .Printf ("Updating %s from build %d to %d" , img , oldnum , newnum )
535+ }
536+ }
537+ }
506538 build .MustRunCommand ("docker" , "image" , "tag" , fmt .Sprintf ("%s:TAG" , * upload ), gethImage )
507539 build .MustRunCommand ("docker" , "image" , "tag" , fmt .Sprintf ("%s:alltools-TAG" , * upload ), toolImage )
508540 build .MustRunCommand ("docker" , "push" , gethImage )
@@ -511,6 +543,59 @@ func doDocker(cmdline []string) {
511543 }
512544 // If multi-arch image manifest push is requested, assemble it
513545 if len (* manifest ) != 0 {
546+ // Since different architectures are pushed by different builders, wait
547+ // until all required images are updated.
548+ var mismatch bool
549+ for i := 0 ; i < 2 ; i ++ { // 2 attempts, second is race check
550+ mismatch = false // hope there's no mismatch now
551+
552+ for _ , tag := range tags {
553+ for _ , arch := range strings .Split (* manifest , "," ) {
554+ gethImage := fmt .Sprintf ("%s:%s-%s" , * upload , tag , arch )
555+ toolImage := fmt .Sprintf ("%s:alltools-%s-%s" , * upload , tag , arch )
556+
557+ for _ , img := range []string {gethImage , toolImage } {
558+ if out , err := exec .Command ("docker" , "pull" , img ).CombinedOutput (); err != nil {
559+ log .Printf ("Required image %s unavailable: %v\n Output: %s" , img , err , out )
560+ mismatch = true
561+ break
562+ }
563+ buildnum , err := exec .Command ("docker" , "inspect" , "--format" , "{{index .Config.Labels \" buildnum\" }}" , img ).CombinedOutput ()
564+ if err != nil {
565+ log .Fatalf ("Failed to inspect container: %v\n Output: %s" , err , string (buildnum ))
566+ }
567+ buildnum = bytes .TrimSpace (buildnum )
568+
569+ if string (buildnum ) != env .Buildnum {
570+ log .Printf ("Build number mismatch on %s: want %s, have %s" , img , env .Buildnum , buildnum )
571+ mismatch = true
572+ break
573+ }
574+ }
575+ if mismatch {
576+ break
577+ }
578+ }
579+ if mismatch {
580+ break
581+ }
582+ }
583+ if mismatch {
584+ // Build numbers mismatching, retry in a short time to
585+ // avoid concurrent failes in both publisher images. If
586+ // however the retry failed too, it means the concurrent
587+ // builder is still crunching, let that do the publish.
588+ if i == 0 {
589+ time .Sleep (30 * time .Second )
590+ }
591+ continue
592+ }
593+ break
594+ }
595+ if mismatch {
596+ log .Println ("Relinquishing publish to other builder" )
597+ return
598+ }
514599 // Assemble and push the Geth manifest image
515600 for _ , tag := range tags {
516601 gethImage := fmt .Sprintf ("%s:%s" , * upload , tag )
0 commit comments