From 6ab14a51eb4eda929bbd8231025e87b782b11ab5 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 6 Nov 2013 15:52:33 +0000 Subject: [PATCH] Add detailed download reporting to AetherGrapeEngine Groovy's Grape allows a user to enable download reports using the system property groovy.grape.report.downloads. This commit updates AetherGrapeEngine to honour this property and produce a detailed download report when the system property is set to true. In the absence of the system property, or when it's set to a value other than true, the existing summary report is still produced. [bs-344] [60145094] --- .../cli/compiler/grape/AetherGrapeEngine.java | 11 ++- .../grape/DetailedProgressReporter.java | 68 +++++++++++++ .../cli/compiler/grape/ProgressReporter.java | 74 ++------------ .../grape/SummaryProgressReporter.java | 97 +++++++++++++++++++ .../grape/AetherGrapeEngineTests.java | 6 +- .../grape/DetailedProgressReporterTests.java | 75 ++++++++++++++ 6 files changed, 262 insertions(+), 69 deletions(-) create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporter.java create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/SummaryProgressReporter.java create mode 100644 spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporterTests.java diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java index f74a016d694..7a5a7e3f660 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java @@ -90,7 +90,7 @@ public class AetherGrapeEngine implements GrapeEngine { session.setLocalRepositoryManager(localRepositoryManager); this.session = session; this.repositories = getRemoteRepositories(); - this.progressReporter = new ProgressReporter(session); + this.progressReporter = getProgressReporter(session); } private ServiceLocator createServiceLocator() { @@ -132,6 +132,15 @@ public class AetherGrapeEngine implements GrapeEngine { repositories.add(new RemoteRepository.Builder(id, "default", url).build()); } + private ProgressReporter getProgressReporter(DefaultRepositorySystemSession session) { + if (Boolean.getBoolean("groovy.grape.report.downloads")) { + return new DetailedProgressReporter(session, System.out); + } + else { + return new SummaryProgressReporter(session, System.out); + } + } + @Override public Object grab(Map args) { return grab(args, args); diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporter.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporter.java new file mode 100644 index 00000000000..9a7cdde8818 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporter.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2013 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.cli.compiler.grape; + +import java.io.PrintStream; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.transfer.AbstractTransferListener; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.transfer.TransferEvent; +import org.eclipse.aether.transfer.TransferResource; + +/** + * Provide detailed progress feedback for long running resolves. + * + * @author Andy Wilkinson + */ +final class DetailedProgressReporter implements ProgressReporter { + + DetailedProgressReporter(DefaultRepositorySystemSession session, final PrintStream out) { + + session.setTransferListener(new AbstractTransferListener() { + + @Override + public void transferStarted(TransferEvent event) + throws TransferCancelledException { + out.println("Downloading: " + getResourceIdentifier(event.getResource())); + } + + @Override + public void transferSucceeded(TransferEvent event) { + out.printf("Downloaded: %s (%s)%n", + getResourceIdentifier(event.getResource()), + getTransferSpeed(event)); + } + }); + } + + private String getResourceIdentifier(TransferResource resource) { + return resource.getRepositoryUrl() + resource.getResourceName(); + } + + private String getTransferSpeed(TransferEvent event) { + long kb = event.getTransferredBytes() / 1024; + float seconds = (System.currentTimeMillis() - event.getResource() + .getTransferStartTime()) / 1000.0f; + + return String.format("%dKB at %.1fKB/sec", kb, (kb / seconds)); + } + + @Override + public void finished() { + } +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/ProgressReporter.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/ProgressReporter.java index 90cea8a2729..3dc0e3cf4b1 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/ProgressReporter.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/ProgressReporter.java @@ -16,76 +16,16 @@ package org.springframework.boot.cli.compiler.grape; -import java.util.concurrent.TimeUnit; - -import org.eclipse.aether.AbstractRepositoryListener; -import org.eclipse.aether.DefaultRepositorySystemSession; -import org.eclipse.aether.RepositoryEvent; -import org.eclipse.aether.transfer.AbstractTransferListener; -import org.eclipse.aether.transfer.TransferCancelledException; -import org.eclipse.aether.transfer.TransferEvent; - /** - * Provide console progress feedback for long running resolves. + * Reports progress on a dependency resolution operation * - * @author Phillip Webb * @author Andy Wilkinson */ -final class ProgressReporter { +interface ProgressReporter { - private static final long INITIAL_DELAY = TimeUnit.SECONDS.toMillis(3); + /** + * Notification that the operation has completed + */ + void finished(); - private static final long PROGRESS_DELAY = TimeUnit.SECONDS.toMillis(1); - - private long startTime = System.currentTimeMillis(); - - private long lastProgressTime = System.currentTimeMillis(); - - private boolean started; - - private boolean finished; - - public ProgressReporter(DefaultRepositorySystemSession session) { - session.setTransferListener(new AbstractTransferListener() { - @Override - public void transferStarted(TransferEvent event) - throws TransferCancelledException { - reportProgress(); - } - - @Override - public void transferProgressed(TransferEvent event) - throws TransferCancelledException { - reportProgress(); - } - }); - - session.setRepositoryListener(new AbstractRepositoryListener() { - @Override - public void artifactResolved(RepositoryEvent event) { - reportProgress(); - } - }); - } - - private void reportProgress() { - if (!this.finished && System.currentTimeMillis() - this.startTime > INITIAL_DELAY) { - if (!this.started) { - this.started = true; - System.out.print("Resolving dependencies.."); - this.lastProgressTime = System.currentTimeMillis(); - } - else if (System.currentTimeMillis() - this.lastProgressTime > PROGRESS_DELAY) { - System.out.print("."); - this.lastProgressTime = System.currentTimeMillis(); - } - } - } - - public void finished() { - if (this.started && !this.finished) { - this.finished = true; - System.out.println(""); - } - } -} +} \ No newline at end of file diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/SummaryProgressReporter.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/SummaryProgressReporter.java new file mode 100644 index 00000000000..7baadb6b601 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/SummaryProgressReporter.java @@ -0,0 +1,97 @@ +/* + * Copyright 2012-2013 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.cli.compiler.grape; + +import java.io.PrintStream; +import java.util.concurrent.TimeUnit; + +import org.eclipse.aether.AbstractRepositoryListener; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.transfer.AbstractTransferListener; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.transfer.TransferEvent; + +/** + * Provide high-level progress feedback for long running resolves. + * + * @author Phillip Webb + * @author Andy Wilkinson + */ +final class SummaryProgressReporter implements ProgressReporter { + + private static final long INITIAL_DELAY = TimeUnit.SECONDS.toMillis(3); + + private static final long PROGRESS_DELAY = TimeUnit.SECONDS.toMillis(1); + + private final long startTime = System.currentTimeMillis(); + + private final PrintStream out; + + private long lastProgressTime = System.currentTimeMillis(); + + private boolean started; + + private boolean finished; + + public SummaryProgressReporter(DefaultRepositorySystemSession session, PrintStream out) { + this.out = out; + + session.setTransferListener(new AbstractTransferListener() { + @Override + public void transferStarted(TransferEvent event) + throws TransferCancelledException { + reportProgress(); + } + + @Override + public void transferProgressed(TransferEvent event) + throws TransferCancelledException { + reportProgress(); + } + }); + + session.setRepositoryListener(new AbstractRepositoryListener() { + @Override + public void artifactResolved(RepositoryEvent event) { + reportProgress(); + } + }); + } + + private void reportProgress() { + if (!this.finished && System.currentTimeMillis() - this.startTime > INITIAL_DELAY) { + if (!this.started) { + this.started = true; + this.out.print("Resolving dependencies.."); + this.lastProgressTime = System.currentTimeMillis(); + } + else if (System.currentTimeMillis() - this.lastProgressTime > PROGRESS_DELAY) { + this.out.print("."); + this.lastProgressTime = System.currentTimeMillis(); + } + } + } + + @Override + public void finished() { + if (this.started && !this.finished) { + this.finished = true; + System.out.println(""); + } + } +} diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java index 80c68803c90..c48ad62e11e 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java @@ -92,7 +92,11 @@ public class AetherGrapeEngineTests { Map args = new HashMap(); System.setProperty("disableSpringSnapshotRepos", "true"); try { - new AetherGrapeEngine(this.groovyClassLoader).grab(args, + AetherGrapeEngine aetherGrapeEngine = new AetherGrapeEngine( + this.groovyClassLoader); + aetherGrapeEngine.addResolver(createResolver("restlet.org", + "http://maven.restlet.org")); + aetherGrapeEngine.grab(args, createDependency("org.springframework", "spring-jdbc", "3.2.0.M1")); } finally { diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporterTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporterTests.java new file mode 100644 index 00000000000..481c5285595 --- /dev/null +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/DetailedProgressReporterTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-2013 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.cli.compiler.grape; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.transfer.TransferCancelledException; +import org.eclipse.aether.transfer.TransferEvent; +import org.eclipse.aether.transfer.TransferResource; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public final class DetailedProgressReporterTests { + + private static final String REPOSITORY = "http://my.repository.com/"; + + private static final String ARTIFACT = "org/alpha/bravo/charlie/1.2.3/charlie-1.2.3.jar"; + + private final TransferResource resource = new TransferResource(REPOSITORY, ARTIFACT, + null, null); + + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + private final PrintStream out = new PrintStream(this.baos); + + private final DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(); + + @Before + public void initialize() { + new DetailedProgressReporter(this.session, this.out); + } + + @Test + public void downloading() throws TransferCancelledException { + TransferEvent startedEvent = new TransferEvent.Builder(this.session, + this.resource).build(); + this.session.getTransferListener().transferStarted(startedEvent); + + assertEquals(String.format("Downloading: %s%s%n", REPOSITORY, ARTIFACT), + new String(this.baos.toByteArray())); + } + + @Test + public void downloaded() throws InterruptedException { + // Ensure some transfer time + Thread.sleep(100); + + TransferEvent completedEvent = new TransferEvent.Builder(this.session, + this.resource).addTransferredBytes(4096).build(); + this.session.getTransferListener().transferSucceeded(completedEvent); + + assertTrue(new String(this.baos.toByteArray()).matches(String.format( + "Downloaded: %s%s \\(4KB at [0-9]+\\.[0-9]KB/sec\\)\\n", REPOSITORY, + ARTIFACT))); + } +}