org.gradle.tooling.internal.consumer.DistributionInstaller Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2017 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.gradle.tooling.internal.consumer;
import org.gradle.internal.UncheckedException;
import org.gradle.internal.logging.progress.ProgressLogger;
import org.gradle.internal.logging.progress.ProgressLoggerFactory;
import org.gradle.internal.time.TimeProvider;
import org.gradle.internal.time.TrueTimeProvider;
import org.gradle.tooling.events.OperationDescriptor;
import org.gradle.tooling.events.OperationResult;
import org.gradle.tooling.events.StatusEvent;
import org.gradle.tooling.events.internal.ConsumerOperationDescriptor;
import org.gradle.tooling.events.internal.DefaultFinishEvent;
import org.gradle.tooling.events.internal.DefaultOperationFailureResult;
import org.gradle.tooling.events.internal.DefaultOperationSuccessResult;
import org.gradle.tooling.events.internal.DefaultStartEvent;
import org.gradle.tooling.events.internal.DefaultStatusEvent;
import org.gradle.tooling.internal.protocol.InternalBuildProgressListener;
import org.gradle.util.GradleVersion;
import org.gradle.wrapper.Download;
import org.gradle.wrapper.DownloadProgressListener;
import org.gradle.wrapper.IDownload;
import org.gradle.wrapper.Install;
import org.gradle.wrapper.Logger;
import org.gradle.wrapper.PathAssembler;
import org.gradle.wrapper.WrapperConfiguration;
import java.io.File;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.atomic.AtomicReference;
public class DistributionInstaller {
private static final String APP_NAME = "Gradle Tooling API";
private static final InternalBuildProgressListener NO_OP = new NoOpListener();
private final ProgressLoggerFactory progressLoggerFactory;
private final InternalBuildProgressListener buildProgressListener;
private final TimeProvider timeProvider;
private final AtomicReference currentListener = new AtomicReference(NO_OP);
// Protects the following state
private final Object lock = new Object();
private boolean completed;
private boolean cancelled;
private Throwable failure;
public DistributionInstaller(ProgressLoggerFactory progressLoggerFactory, InternalBuildProgressListener buildProgressListener) {
this.progressLoggerFactory = progressLoggerFactory;
this.buildProgressListener = buildProgressListener;
this.timeProvider = new TrueTimeProvider();
}
/**
* Installs the distribution and returns the result.
*/
public File install(File userHomeDir, WrapperConfiguration wrapperConfiguration) throws Exception {
Install install = new Install(new Logger(false), new AsyncDownload(), new PathAssembler(userHomeDir));
return install.createDist(wrapperConfiguration);
}
/**
* Cancels the current installation, if running.
*/
public void cancel() {
synchronized (lock) {
cancelled = true;
lock.notifyAll();
}
}
private void doDownload(URI address, File destination) throws Exception {
String displayName = "Download " + address;
OperationDescriptor descriptor = new ConsumerOperationDescriptor(displayName);
long startTime = timeProvider.getCurrentTime();
buildProgressListener.onEvent(new DefaultStartEvent(startTime, displayName + " started", descriptor));
Throwable failure = null;
try {
withProgressLogging(address, destination, descriptor);
} catch (Throwable t) {
failure = t;
}
long endTime = timeProvider.getCurrentTime();
OperationResult result = failure == null ? new DefaultOperationSuccessResult(startTime, endTime) : new DefaultOperationFailureResult(startTime, endTime, Collections.singletonList(DefaultFailure.fromThrowable(failure)));
buildProgressListener.onEvent(new DefaultFinishEvent(endTime, displayName + " finished", descriptor, result));
if (failure != null) {
if (failure instanceof Exception) {
throw (Exception) failure;
}
throw UncheckedException.throwAsUncheckedException(failure);
}
}
private void withProgressLogging(URI address, File destination, OperationDescriptor operationDescriptor) throws Throwable {
ProgressLogger progressLogger = progressLoggerFactory.newOperation(DistributionInstaller.class);
progressLogger.setDescription("Download " + address);
progressLogger.started();
try {
withAsyncDownload(address, destination, operationDescriptor);
} finally {
progressLogger.completed();
}
}
private void withAsyncDownload(final URI address, final File destination, final OperationDescriptor operationDescriptor) throws Throwable {
currentListener.set(buildProgressListener);
try {
// Start the download in another thread and wait for the result
Thread thread = new Thread("Distribution download") {
@Override
public void run() {
try {
new Download(new Logger(false), new ForwardingDownloadProgressListener(operationDescriptor), APP_NAME, GradleVersion.current().getVersion()).download(address, destination);
} catch (Throwable t) {
synchronized (lock) {
failure = t;
}
} finally {
synchronized (lock) {
completed = true;
lock.notifyAll();
}
}
}
};
thread.setDaemon(true);
thread.start();
synchronized (lock) {
while (!completed && !cancelled) {
try {
lock.wait();
} catch (InterruptedException e) {
throw UncheckedException.throwAsUncheckedException(e);
}
}
if (failure != null) {
throw failure;
}
if (cancelled) {
// When cancelled, try to stop the download thread but don't attempt to wait for it to complete
// Could possibly loop here for a while trying to force the thread to exit
thread.interrupt();
throw new CancellationException();
}
}
} finally {
// The download thread may still be running. Ignore any further status events from it
currentListener.set(NO_OP);
}
}
private static class NoOpListener implements InternalBuildProgressListener {
@Override
public void onEvent(Object event) {
}
@Override
public List getSubscribedOperations() {
return Collections.emptyList();
}
}
private class ForwardingDownloadProgressListener implements DownloadProgressListener {
private final OperationDescriptor descriptor;
ForwardingDownloadProgressListener(OperationDescriptor descriptor) {
this.descriptor = descriptor;
}
@Override
public void downloadStatusChanged(URI address, long contentLength, long downloaded) {
String eventDisplayName = descriptor.getDisplayName() + " " + downloaded + "/" + contentLength + " bytes downloaded";
StatusEvent statusEvent = new DefaultStatusEvent(timeProvider.getCurrentTime(), eventDisplayName, descriptor, contentLength, downloaded, "bytes");
// This is called from the download thread. Only forward the events when not cancelled
currentListener.get().onEvent(statusEvent);
}
}
private class AsyncDownload implements IDownload {
@Override
public void download(URI address, File destination) throws Exception {
synchronized (lock) {
doDownload(address, destination);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy