Skip to content

Commit

Permalink
Issue #58: Progress report for Installing
Browse files Browse the repository at this point in the history
 - Add a progress dialog to the installation process
 - Use the output of the toolchain downloading commands to give the user
more info
 - Fix typo in messages
 - Abstracted running commands to a new Job class

Signed-off-by: Lucas Bullen <[email protected]>
  • Loading branch information
Lucas Bullen committed Jun 1, 2018
1 parent 8e247ac commit f2af9a5
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 95 deletions.
78 changes: 78 additions & 0 deletions org.eclipse.corrosion/src/org/eclipse/corrosion/CommandJob.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*********************************************************************
* Copyright (c) 2018 Red Hat Inc. and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Lucas Bullen (Red Hat Inc.) - Initial implementation
*******************************************************************************/
package org.eclipse.corrosion;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.CompletableFuture;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;

public class CommandJob extends Job {
private Process process;
private String[] command;
private String progressMessage;
private String errorTitle;
private String errorMessage;
private int expectedWork;

public CommandJob(String[] command, String progressMessage, String errorTitle, String errorMessage,
int expectedWork) {
super(progressMessage);
this.command = command;
this.progressMessage = progressMessage;
this.errorTitle = errorTitle;
this.errorMessage = errorMessage;
this.expectedWork = expectedWork;
}

@Override
protected IStatus run(IProgressMonitor monitor) {
SubMonitor subMonitor = SubMonitor.convert(monitor, expectedWork);
try {
subMonitor.beginTask(progressMessage, expectedWork);
process = new ProcessBuilder(command).start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
CompletableFuture.runAsync(() -> {
reader.lines().forEachOrdered(line -> {
subMonitor.subTask(line);
if (expectedWork > 0) {
subMonitor.worked(1);
}
});
});
if (process.waitFor() != 0) {
if (!subMonitor.isCanceled()) {
CorrosionPlugin.showError(errorTitle, errorMessage);
}
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
} catch (IOException | InterruptedException e) {
CorrosionPlugin.showError(errorTitle, errorMessage, e);
return Status.CANCEL_STATUS;
}
}

@Override
protected void canceling() {
if (process != null) {
process.destroyForcibly();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

Expand Down Expand Up @@ -55,4 +59,17 @@ public static CorrosionPlugin getDefault() {
public static void logError(Throwable t) {
getDefault().getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, t.getMessage(), t));
}

public static void showError(String title, String message, Exception exception) {
CorrosionPlugin.showError(title, message + '\n' + exception.getLocalizedMessage());
}

public static void showError(String title, String message) {
Display.getDefault().asyncExec(() -> {
MessageDialog dialog = new MessageDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
title, null, message, MessageDialog.ERROR, 0, IDialogConstants.OK_LABEL);
dialog.setBlockOnOpen(false);
dialog.open();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
import java.util.List;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.ICoreRunnable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.swt.SWT;
Expand Down Expand Up @@ -382,34 +382,43 @@ private void createCommandPathsPart(Composite container) {
private void installCommands() {
installButton.setText(Messages.CorrosionPreferencePage_installing);
installButton.setEnabled(false);
Job.create(Messages.CorrosionPreferencePage_installingRustupCargo, (ICoreRunnable) monitor -> {
try {
Bundle bundle = CorrosionPlugin.getDefault().getBundle();
URL fileURL = FileLocator.toFileURL(bundle.getEntry("scripts/rustup-init.sh")); //$NON-NLS-1$
File file = new File(new URI(fileURL.getProtocol(), fileURL.getPath(), null));
file.setExecutable(true);
String[] command = new String[] { "/bin/bash", "-c", file.getAbsolutePath() + " -y" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
if (process.waitFor() == 0) {

String[] command;
try {
Bundle bundle = CorrosionPlugin.getDefault().getBundle();
URL fileURL = FileLocator.toFileURL(bundle.getEntry("scripts/rustup-init.sh")); //$NON-NLS-1$
File file = new File(new URI(fileURL.getProtocol(), fileURL.getPath(), null));
file.setExecutable(true);
command = new String[] { "/bin/bash", "-c", file.getAbsolutePath() + " -y" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} catch (IOException | URISyntaxException e) {
CorrosionPlugin.showError(Messages.CorrosionPreferencePage_cannotInstallRustupCargo,
Messages.CorrosionPreferencePage_cannotInstallRustupCargo_details, e);
return;
}

CommandJob installCommandJob = new CommandJob(command, Messages.CorrosionPreferencePage_installingRustupCargo,
Messages.CorrosionPreferencePage_cannotInstallRustupCargo,
Messages.CorrosionPreferencePage_cannotInstallRustupCargo_details, 15);
installCommandJob.setUser(true);
installCommandJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(final IJobChangeEvent event) {
if (event.getResult() == Status.OK_STATUS) {
CorrosionPreferenceInitializer initializer = new CorrosionPreferenceInitializer();
initializer.initializeDefaultPreferences();
Display.getDefault().asyncExec(() -> {
if (installButton.isDisposed()) {
return;
}
setInstallRequired(false);
performDefaults();
setValid(isPageValid());
});
RustManager.setDefaultToolchain("beta"); //$NON-NLS-1$
return;
}
} catch (InterruptedException | URISyntaxException | IOException e) {
// will be caught with dialog
}
Display.getDefault().asyncExec(() -> {
setInstallRequired(true);
MessageDialog.openError(getShell(), Messages.CorrosionPreferencePage_cannotInstallRustupCargo, Messages.CorrosionPreferencePage_cannotInstallRustupCargo_details);
});
}).schedule();
});
installCommandJob.schedule();
}

private void setInstallRequired(Boolean required) {
Expand Down
124 changes: 51 additions & 73 deletions org.eclipse.corrosion/src/org/eclipse/corrosion/RustManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,23 @@
package org.eclipse.corrosion;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IDocument;
import org.eclipse.lsp4e.LanguageServiceAccessor;
import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
import org.eclipse.lsp4j.DidChangeConfigurationParams;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPage;
Expand Down Expand Up @@ -83,47 +82,45 @@ public static void setDefaultToolchain(String toolchainId) {
if (settingToolchainJob != null) {
settingToolchainJob.cancel();
}

settingToolchainJob = Job.create(Messages.RustManager_settingRLSToolchain, monitor -> {
SubMonitor subMonitor = SubMonitor.convert(monitor, 5);
subMonitor.beginTask(Messages.RustManager_installingToolchain, 5);
subMonitor.split(1);
if (!runRustupCommand(subMonitor, "toolchain", "install", toolchainId)) { //$NON-NLS-1$ //$NON-NLS-2$
if (!monitor.isCanceled()) {
showToolchainSelectionError(NLS.bind(Messages.RustManager_unableToInstallToolchain, toolchainId));
}
return;
}
subMonitor.subTask(Messages.RustManager_settingDefaultToolchain);
subMonitor.split(1);
if (!runRustupCommand(subMonitor, "default", toolchainId)) { //$NON-NLS-1$
if (!monitor.isCanceled()) {
showToolchainSelectionError(NLS.bind(Messages.RustManager_unableToSetDefaultToolchain, toolchainId));
}
return;
}
subMonitor.subTask(Messages.RustManager_addingRLSPrevios);
subMonitor.split(1);
if (!runRustupCommand(subMonitor, "component", "add", "rls-preview")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (!monitor.isCanceled()) {
showToolchainSelectionError(NLS.bind(Messages.RustManager_toolchainDoesntIncludeRLS, toolchainId));
settingToolchainJob = new Job(Messages.RustManager_settingRLSToolchain) {
CommandJob currentCommandJob;

@Override
protected IStatus run(IProgressMonitor monitor) {
List<CommandJob> jobs = new ArrayList<>();
jobs.add(createRustupCommandJob(Messages.RustManager_installingToolchain,
NLS.bind(Messages.RustManager_unableToInstallToolchain, toolchainId), "toolchain", "install", //$NON-NLS-1$ //$NON-NLS-2$
toolchainId));
jobs.add(createRustupCommandJob(Messages.RustManager_settingDefaultToolchain,
NLS.bind(Messages.RustManager_unableToSetDefaultToolchain, toolchainId), "default", //$NON-NLS-1$
toolchainId));
jobs.add(createRustupCommandJob(Messages.RustManager_addingRLSPrevios,
NLS.bind(Messages.RustManager_toolchainDoesntIncludeRLS, toolchainId), "component", "add", //$NON-NLS-1$ //$NON-NLS-2$
"rls-preview")); //$NON-NLS-1$
jobs.add(createRustupCommandJob(Messages.RustManager_addingRustAnalysisRustSrc,
Messages.RustManager_unableToAddComponent, "component", //$NON-NLS-1$
"add", "rust-analysis")); //$NON-NLS-1$ //$NON-NLS-2$

for (CommandJob commandJob : jobs) {
currentCommandJob = commandJob;
if (currentCommandJob.run(monitor) == Status.CANCEL_STATUS) {
return Status.CANCEL_STATUS;
}
monitor.worked(1);
}
return;
Map<String, String> updatedSettings = new HashMap<>();
updatedSettings.put("target", toolchainId); //$NON-NLS-1$
sendDidChangeConfigurationsMessage(updatedSettings);
return Status.OK_STATUS;
}
subMonitor.subTask(Messages.RustManager_addingRustAnalysisRustSrc);
subMonitor.split(1);
if (!runRustupCommand(subMonitor, "component", "add", "rust-analysis") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|| !runRustupCommand(subMonitor, "component", "add", "rust-src")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (!monitor.isCanceled()) {
showToolchainSelectionError(Messages.RustManager_unableToAddComponent);

@Override
protected void canceling() {
if (currentCommandJob != null) {
currentCommandJob.cancel();
}
return;
}
Map<String, String> updatedSettings = new HashMap<>();
updatedSettings.put("target", toolchainId); //$NON-NLS-1$

sendDidChangeConfigurationsMessage(updatedSettings);
});
};
settingToolchainJob.schedule();
}

Expand All @@ -136,6 +133,19 @@ private static void sendDidChangeConfigurationsMessage(Map<String, String> updat
}
}

private static CommandJob createRustupCommandJob(String progressMessage, String errorMessage, String... arguments) {
String rustup = STORE.getString(CorrosionPreferenceInitializer.rustupPathPreference);
if (rustup.isEmpty()) {
return null;
}
String[] command = new String[arguments.length + 1];
command[0] = rustup;
System.arraycopy(arguments, 0, command, 1, arguments.length);
CommandJob commandJob = new CommandJob(command, progressMessage,
Messages.RustManager_rootToolchainSelectionFailure, errorMessage, 0);
return commandJob;
}

private static LSPDocumentInfo infoFromOpenEditors() {
for (IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
for (IWorkbenchPage page : window.getPages()) {
Expand All @@ -160,38 +170,6 @@ private static LSPDocumentInfo infoFromOpenEditors() {
return null;
}

private static void showToolchainSelectionError(String message) {
Display.getDefault().asyncExec(() -> {
MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.RustManager_rootToolchainSelectionFailure, message);
});
}

private static boolean runRustupCommand(SubMonitor monitor, String... arguments) {
String rustup = STORE.getString(CorrosionPreferenceInitializer.rustupPathPreference);
if (rustup.isEmpty()) {
return false;
}
try {
String[] command = new String[arguments.length + 1];
command[0] = rustup;
System.arraycopy(arguments, 0, command, 1, arguments.length);
ProcessBuilder builder = new ProcessBuilder(command);
builder.inheritIO();
Process process = builder.start();
while (process.isAlive() && !monitor.isCanceled()) {
Thread.sleep(50);
}
if (monitor.isCanceled()) {
process.destroyForcibly();
return false;
}

return process.waitFor() == 0;
} catch (IOException | InterruptedException e) {
return false;
}
}

public static List<String> getToolchains() {
List<String> toolchainsList = new ArrayList<>();
String rustup = STORE.getString(CorrosionPreferenceInitializer.rustupPathPreference);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ ToggleBreakpointsTargetFactory_breakpointTarget=Breakpoint for native Rust code.
CargoTestTab_testName=Test Name:
CargoTestTab_testNameDescription=If specified, only run tests containing this string in their names
CargoExportWizard_cannotCreateProject_details=Create unsuccessful. `{0}` error log:\n\n {1}
CargoExportwizard_commandFailed=Command `{0}` failed: {1}
CargoExportWizard_commandFailed=Command `{0}` failed: {1}
CargoExportWizard_cannotCreateProject=Cannot Create Rust Project
CargoExportWizard_cannotPackageProject=Cannot Package Cargo Based Rust Project
CargoExportWizard_title=Package Cargo Based Rust Project
Expand Down

0 comments on commit f2af9a5

Please sign in to comment.