public boolean pushBlob(
      DescriptorDigest blobDigest,
      Blob blob,
      @Nullable String sourceRepository,
      Consumer<Long> writtenByteCountListener)
      throws IOException, RegistryException {
    if (isBearerAuth(authorization.get()) && readOnlyBearerAuth) {
      throw new IllegalStateException("push may fail with pull-only bearer auth token");
    }

    if (sourceRepository != null
        && !(JibSystemProperties.useCrossRepositoryBlobMounts()
            && canAttemptBlobMount(authorization.get(), sourceRepository))) {
      // don't bother requesting a cross-repository blob-mount if we don't have access
      sourceRepository = null;
    }
    BlobPusher blobPusher =
        new BlobPusher(registryEndpointRequestProperties, blobDigest, blob, sourceRepository);

    try (TimerEventDispatcher timerEventDispatcher =
        new TimerEventDispatcher(eventHandlers, "pushBlob")) {
      try (TimerEventDispatcher timerEventDispatcher2 =
          timerEventDispatcher.subTimer("pushBlob POST " + blobDigest)) {

        // POST /v2/<name>/blobs/uploads/?mount={blob.digest}&from={sourceRepository}
        // POST /v2/<name>/blobs/uploads/
        Optional<URL> patchLocation = callRegistryEndpoint(blobPusher.initializer());
        if (!patchLocation.isPresent()) {
          // The BLOB exists already.
          return true;
        }

        timerEventDispatcher2.lap("pushBlob PATCH " + blobDigest);

        // PATCH <Location> with BLOB
        URL putLocation =
            callRegistryEndpoint(blobPusher.writer(patchLocation.get(), writtenByteCountListener));

        timerEventDispatcher2.lap("pushBlob PUT " + blobDigest);

        // PUT <Location>?digest={blob.digest}
        callRegistryEndpoint(blobPusher.committer(putLocation));

        return false;
      }
    }
  }
Pushes the BLOB. If the {@code sourceRepository} is provided then the remote registry may skip
if the BLOB already exists on the registry.

@param blobDigest the digest of the BLOB, used for existence-check
@param blob the BLOB to push
@param sourceRepository if pushing to the same registry then the source image, or {@code null}
    otherwise; used to optimize the BLOB push
@param writtenByteCountListener listens on byte count written to the registry during the push
@return {@code true} if the BLOB already exists on the registry and pushing was skipped; false
    if the BLOB was pushed
@throws IOException if communicating with the endpoint fails
@throws RegistryException if communicating with the endpoint fails
jib-core/src/main/java/com/google/cloud/tools/jib/registry/RegistryClient.java