From d8565185e81ab11cd25c583809b871c7662862cb Mon Sep 17 00:00:00 2001 From: Wolfgang Kronberg Date: Fri, 29 Nov 2024 14:14:53 +0100 Subject: [PATCH 1/2] Accept Docker progress on numbers >2GB Update `ProgressUpdateEvent` to support images of a file size >2GB without provoking build failures. See gh-43328 --- .../platform/docker/ProgressUpdateEvent.java | 11 ++++++----- .../docker/ProgressUpdateEventTests.java | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java index 271b6c19a2bd..5226ac57e3ce 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java @@ -22,6 +22,7 @@ * An {@link UpdateEvent} that includes progress information. * * @author Phillip Webb + * @author Wolfgang Kronberg * @since 2.3.0 */ public abstract class ProgressUpdateEvent extends UpdateEvent { @@ -67,12 +68,12 @@ public String getProgress() { */ public static class ProgressDetail { - private final Integer current; + private final Long current; - private final Integer total; + private final Long total; @JsonCreator - public ProgressDetail(Integer current, Integer total) { + public ProgressDetail(Long current, Long total) { this.current = current; this.total = total; } @@ -81,7 +82,7 @@ public ProgressDetail(Integer current, Integer total) { * Return the current progress value. * @return the current progress */ - public int getCurrent() { + public long getCurrent() { return this.current; } @@ -89,7 +90,7 @@ public int getCurrent() { * Return the total progress possible value. * @return the total progress possible */ - public int getTotal() { + public long getTotal() { return this.total; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java index d6e2c0ace472..063e17ffc3a5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java @@ -28,6 +28,7 @@ * @param The event type * @author Phillip Webb * @author Scott Frederick + * @author Wolfgang Kronberg */ abstract class ProgressUpdateEventTests { @@ -44,6 +45,13 @@ void getProgressDetailsReturnsProgressDetails() { assertThat(event.getProgressDetail().getTotal()).isEqualTo(2); } + @Test + void getProgressDetailsReturnsProgressDetailsForLongNumbers() { + ProgressUpdateEvent event = createEvent("status", new ProgressDetail(4000000000L, 8000000000L), "progress"); + assertThat(event.getProgressDetail().getCurrent()).isEqualTo(4000000000L); + assertThat(event.getProgressDetail().getTotal()).isEqualTo(8000000000L); + } + @Test void getProgressReturnsProgress() { ProgressUpdateEvent event = createEvent(); @@ -52,24 +60,24 @@ void getProgressReturnsProgress() { @Test void progressDetailIsEmptyWhenCurrentIsNullReturnsTrue() { - ProgressDetail detail = new ProgressDetail(null, 2); + ProgressDetail detail = new ProgressDetail(null, 2L); assertThat(ProgressDetail.isEmpty(detail)).isTrue(); } @Test void progressDetailIsEmptyWhenTotalIsNullReturnsTrue() { - ProgressDetail detail = new ProgressDetail(1, null); + ProgressDetail detail = new ProgressDetail(1L, null); assertThat(ProgressDetail.isEmpty(detail)).isTrue(); } @Test void progressDetailIsEmptyWhenTotalAndCurrentAreNotNullReturnsFalse() { - ProgressDetail detail = new ProgressDetail(1, 2); + ProgressDetail detail = new ProgressDetail(1L, 2L); assertThat(ProgressDetail.isEmpty(detail)).isFalse(); } protected E createEvent() { - return createEvent("status", new ProgressDetail(1, 2), "progress"); + return createEvent("status", new ProgressDetail(1L, 2L), "progress"); } protected abstract E createEvent(String status, ProgressDetail progressDetail, String progress); From 0afbc0b23cc330e22bc58257ef2f9c2e11e66a94 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 2 Dec 2024 13:55:59 -0800 Subject: [PATCH 2/2] Polish 'Accept Docker progress on numbers >2GB' Restore `int` returns for existing methods and deprecate them in favor of a new `asPercentage()` method. See gh-43328 --- .../platform/docker/ProgressUpdateEvent.java | 33 ++++++++++++++++--- .../docker/TotalProgressListener.java | 10 ++---- .../docker/ProgressUpdateEventTests.java | 13 ++++++-- .../platform/docker/PullUpdateEventTests.java | 4 ++- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java index 5226ac57e3ce..6ac289436341 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,19 +81,42 @@ public ProgressDetail(Long current, Long total) { /** * Return the current progress value. * @return the current progress + * @deprecated since 3.3.7 for removal in 3.5.0 in favor of + * {@link #asPercentage()} */ - public long getCurrent() { - return this.current; + @Deprecated(since = "3.3.7", forRemoval = true) + public int getCurrent() { + return (int) Long.min(this.current, Integer.MAX_VALUE); } /** * Return the total progress possible value. * @return the total progress possible + * @deprecated since 3.3.7 for removal in 3.5.0 in favor of + * {@link #asPercentage()} */ - public long getTotal() { - return this.total; + @Deprecated(since = "3.3.7", forRemoval = true) + public int getTotal() { + return (int) Long.min(this.total, Integer.MAX_VALUE); } + /** + * Return the progress as a percentage. + * @return the progress percentage + * @since 3.3.7 + */ + public int asPercentage() { + int percentage = (int) ((100.0 / this.total) * this.current); + return (percentage < 0) ? 0 : Math.min(percentage, 100); + } + + /** + * Return if the progress detail is considered empty. + * @param progressDetail the progress detail to check + * @return if the progress detail is empty + * @deprecated since 3.3.7 for removal in 3.5.0 + */ + @Deprecated(since = "3.3.7", forRemoval = true) public static boolean isEmpty(ProgressDetail progressDetail) { return progressDetail == null || progressDetail.current == null || progressDetail.total == null; } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java index fa397c611f57..b81cfb85a364 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,10 +89,7 @@ private void publish(int fallback) { } private static int withinPercentageBounds(int value) { - if (value < 0) { - return 0; - } - return Math.min(value, 100); + return (value < 0) ? 0 : Math.min(value, 100); } /** @@ -115,8 +112,7 @@ void update(ImageProgressUpdateEvent event) { } private int updateProgress(int current, ProgressDetail detail) { - int result = withinPercentageBounds((int) ((100.0 / detail.getTotal()) * detail.getCurrent())); - return Math.max(result, current); + return Math.max(detail.asPercentage(), current); } void finish() { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java index 063e17ffc3a5..dd43af828992 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,17 +39,21 @@ void getStatusReturnsStatus() { } @Test + @SuppressWarnings("removal") void getProgressDetailsReturnsProgressDetails() { ProgressUpdateEvent event = createEvent(); assertThat(event.getProgressDetail().getCurrent()).isOne(); assertThat(event.getProgressDetail().getTotal()).isEqualTo(2); + assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50); } @Test + @SuppressWarnings("removal") void getProgressDetailsReturnsProgressDetailsForLongNumbers() { ProgressUpdateEvent event = createEvent("status", new ProgressDetail(4000000000L, 8000000000L), "progress"); - assertThat(event.getProgressDetail().getCurrent()).isEqualTo(4000000000L); - assertThat(event.getProgressDetail().getTotal()).isEqualTo(8000000000L); + assertThat(event.getProgressDetail().getCurrent()).isEqualTo(Integer.MAX_VALUE); + assertThat(event.getProgressDetail().getTotal()).isEqualTo(Integer.MAX_VALUE); + assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50); } @Test @@ -59,18 +63,21 @@ void getProgressReturnsProgress() { } @Test + @SuppressWarnings("removal") void progressDetailIsEmptyWhenCurrentIsNullReturnsTrue() { ProgressDetail detail = new ProgressDetail(null, 2L); assertThat(ProgressDetail.isEmpty(detail)).isTrue(); } @Test + @SuppressWarnings("removal") void progressDetailIsEmptyWhenTotalIsNullReturnsTrue() { ProgressDetail detail = new ProgressDetail(1L, null); assertThat(ProgressDetail.isEmpty(detail)).isTrue(); } @Test + @SuppressWarnings("removal") void progressDetailIsEmptyWhenTotalAndCurrentAreNotNullReturnsFalse() { ProgressDetail detail = new ProgressDetail(1L, 2L); assertThat(ProgressDetail.isEmpty(detail)).isFalse(); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java index 79bb5fd97bd6..7c95f9bcbd0f 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ class PullUpdateEventTests extends AbstractJsonTests { @Test + @SuppressWarnings("removal") void readValueWhenFullDeserializesJson() throws Exception { PullImageUpdateEvent event = getObjectMapper().readValue(getContent("pull-update-full.json"), PullImageUpdateEvent.class); @@ -37,6 +38,7 @@ void readValueWhenFullDeserializesJson() throws Exception { assertThat(event.getStatus()).isEqualTo("Extracting"); assertThat(event.getProgressDetail().getCurrent()).isEqualTo(16); assertThat(event.getProgressDetail().getTotal()).isEqualTo(32); + assertThat(event.getProgressDetail().asPercentage()).isEqualTo(50); assertThat(event.getProgress()).isEqualTo("[==================================================>] 32B/32B"); }