From 063ab089db6433cab65690638940ba67ce32cfb9 Mon Sep 17 00:00:00 2001 From: Doug Schaefer Date: Sat, 10 Oct 2015 19:18:48 -0400 Subject: [PATCH] Improve robustness of downloads and add license confirmation. Bad things were happening when the downloads of the tools and sdk failed. Added retries and changed the order of the downloads so that partial downloads aren't registered as complete. Also added license confirmation dialog to make sure the user agrees to the Arduino licenses before installing the tools and sdk. Change-Id: Ie8f4fcd041d8e89195bc7d3551c63fd3270881ef --- .../core/internal/ArduinoPreferences.java | 3 +- .../core/internal/board/ArduinoManager.java | 154 ++++++++++-------- .../core/internal/board/ArduinoPlatform.java | 27 ++- .../ArduinoBoardsPreferencePage.java | 22 +++ 4 files changed, 118 insertions(+), 88 deletions(-) diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java index 534b0dc2c74..16053b863f9 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoPreferences.java @@ -21,7 +21,8 @@ public class ArduinoPreferences { private static final String defaultHome = Paths.get(System.getProperty("user.home"), ".arduinocdt").toString(); //$NON-NLS-1$ //$NON-NLS-2$ private static final String defaultBoardUrls = "http://downloads.arduino.cc/packages/package_index.json" //$NON-NLS-1$ - + "\nhttp://arduino.esp8266.com/stable/package_esp8266com_index.json"; //$NON-NLS-1$ + + "\r\nhttp://arduino.esp8266.com/stable/package_esp8266com_index.json" //$NON-NLS-1$ + + "\r\nhttps://adafruit.github.io/arduino-board-index/package_adafruit_index.json"; //$NON-NLS-1$ private static IEclipsePreferences getPrefs() { return InstanceScope.INSTANCE.getNode(Activator.getId()); diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java index 20a98296f0d..edf0f709380 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java @@ -19,6 +19,7 @@ import java.io.InputStream; import java.io.Reader; import java.lang.reflect.Type; import java.net.URL; +import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -68,20 +69,23 @@ public class ArduinoManager { public static final String AVR_TOOLCHAIN_ID = "org.eclipse.cdt.arduino.toolChain.avr"; //$NON-NLS-1$ public static final String LIBRARIES_URL = "http://downloads.arduino.cc/libraries/library_index.json"; //$NON-NLS-1$ + private List packageIndices; private LibraryIndex libraryIndex; public void loadIndices() { new Job(Messages.ArduinoBoardManager_0) { protected IStatus run(IProgressMonitor monitor) { - String[] boardUrls = ArduinoPreferences.getBoardUrls().split("\n"); //$NON-NLS-1$ - packageIndices = new ArrayList<>(boardUrls.length); - for (String boardUrl : boardUrls) { - loadPackageIndex(boardUrl, true); - } + synchronized (ArduinoManager.this) { + String[] boardUrls = ArduinoPreferences.getBoardUrls().split("\n"); //$NON-NLS-1$ + packageIndices = new ArrayList<>(boardUrls.length); + for (String boardUrl : boardUrls) { + loadPackageIndex(boardUrl, true); + } - loadLibraryIndex(true); - return Status.OK_STATUS; + loadLibraryIndex(true); + return Status.OK_STATUS; + } } }.schedule(); } @@ -270,83 +274,93 @@ public class ArduinoManager { public static IStatus downloadAndInstall(String url, String archiveFileName, Path installPath, IProgressMonitor monitor) { - try { - URL dl = new URL(url); - Path dlDir = ArduinoPreferences.getArduinoHome().resolve("downloads"); //$NON-NLS-1$ - Files.createDirectories(dlDir); - Path archivePath = dlDir.resolve(archiveFileName); - Files.copy(dl.openStream(), archivePath, StandardCopyOption.REPLACE_EXISTING); - - boolean isWin = Platform.getOS().equals(Platform.OS_WIN32); - - // extract - ArchiveInputStream archiveIn = null; + Exception error = null; + for (int retries = 3; retries > 0 && !monitor.isCanceled(); --retries) { try { - String compressor = null; - String archiver = null; - if (archiveFileName.endsWith("tar.bz2")) { //$NON-NLS-1$ - compressor = CompressorStreamFactory.BZIP2; - archiver = ArchiveStreamFactory.TAR; - } else if (archiveFileName.endsWith(".tar.gz") || archiveFileName.endsWith(".tgz")) { //$NON-NLS-1$ //$NON-NLS-2$ - compressor = CompressorStreamFactory.GZIP; - archiver = ArchiveStreamFactory.TAR; - } else if (archiveFileName.endsWith(".tar.xz")) { //$NON-NLS-1$ - compressor = CompressorStreamFactory.XZ; - archiver = ArchiveStreamFactory.TAR; - } else if (archiveFileName.endsWith(".zip")) { //$NON-NLS-1$ - archiver = ArchiveStreamFactory.ZIP; - } + URL dl = new URL(url); + Path dlDir = ArduinoPreferences.getArduinoHome().resolve("downloads"); //$NON-NLS-1$ + Files.createDirectories(dlDir); + Path archivePath = dlDir.resolve(archiveFileName); + URLConnection conn = dl.openConnection(); + conn.setConnectTimeout(10000); + conn.setReadTimeout(10000); + Files.copy(conn.getInputStream(), archivePath, StandardCopyOption.REPLACE_EXISTING); - InputStream in = new BufferedInputStream(new FileInputStream(archivePath.toFile())); - if (compressor != null) { - in = new CompressorStreamFactory().createCompressorInputStream(compressor, in); - } - archiveIn = new ArchiveStreamFactory().createArchiveInputStream(archiver, in); + boolean isWin = Platform.getOS().equals(Platform.OS_WIN32); - for (ArchiveEntry entry = archiveIn.getNextEntry(); entry != null; entry = archiveIn.getNextEntry()) { - if (entry.isDirectory()) { - continue; + // extract + ArchiveInputStream archiveIn = null; + try { + String compressor = null; + String archiver = null; + if (archiveFileName.endsWith("tar.bz2")) { //$NON-NLS-1$ + compressor = CompressorStreamFactory.BZIP2; + archiver = ArchiveStreamFactory.TAR; + } else if (archiveFileName.endsWith(".tar.gz") || archiveFileName.endsWith(".tgz")) { //$NON-NLS-1$ //$NON-NLS-2$ + compressor = CompressorStreamFactory.GZIP; + archiver = ArchiveStreamFactory.TAR; + } else if (archiveFileName.endsWith(".tar.xz")) { //$NON-NLS-1$ + compressor = CompressorStreamFactory.XZ; + archiver = ArchiveStreamFactory.TAR; + } else if (archiveFileName.endsWith(".zip")) { //$NON-NLS-1$ + archiver = ArchiveStreamFactory.ZIP; } - Path entryPath = installPath.resolve(entry.getName()); - Files.createDirectories(entryPath.getParent()); + InputStream in = new BufferedInputStream(new FileInputStream(archivePath.toFile())); + if (compressor != null) { + in = new CompressorStreamFactory().createCompressorInputStream(compressor, in); + } + archiveIn = new ArchiveStreamFactory().createArchiveInputStream(archiver, in); - if (entry instanceof TarArchiveEntry) { - TarArchiveEntry tarEntry = (TarArchiveEntry) entry; - if (tarEntry.isLink()) { - Path linkPath = installPath.resolve(tarEntry.getLinkName()); - Files.createSymbolicLink(entryPath, entryPath.getParent().relativize(linkPath)); + for (ArchiveEntry entry = archiveIn.getNextEntry(); entry != null; entry = archiveIn + .getNextEntry()) { + if (entry.isDirectory()) { + continue; + } + + Path entryPath = installPath.resolve(entry.getName()); + Files.createDirectories(entryPath.getParent()); + + if (entry instanceof TarArchiveEntry) { + TarArchiveEntry tarEntry = (TarArchiveEntry) entry; + if (tarEntry.isLink()) { + Path linkPath = installPath.resolve(tarEntry.getLinkName()); + Files.createSymbolicLink(entryPath, entryPath.getParent().relativize(linkPath)); + } else { + Files.copy(archiveIn, entryPath, StandardCopyOption.REPLACE_EXISTING); + } + if (!isWin) { + int mode = tarEntry.getMode(); + Files.setPosixFilePermissions(entryPath, toPerms(mode)); + } } else { Files.copy(archiveIn, entryPath, StandardCopyOption.REPLACE_EXISTING); } - if (!isWin) { - int mode = tarEntry.getMode(); - Files.setPosixFilePermissions(entryPath, toPerms(mode)); - } - } else { - Files.copy(archiveIn, entryPath, StandardCopyOption.REPLACE_EXISTING); + } + } finally { + if (archiveIn != null) { + archiveIn.close(); } } - } finally { - if (archiveIn != null) { - archiveIn.close(); - } - } - // Fix up directory - File[] children = installPath.toFile().listFiles(); - if (children.length == 1 && children[0].isDirectory()) { - // make that directory the install path - Path childPath = children[0].toPath(); - Path tmpPath = installPath.getParent().resolve("_t"); //$NON-NLS-1$ - Files.move(childPath, tmpPath); - Files.delete(installPath); - Files.move(tmpPath, installPath); + // Fix up directory + File[] children = installPath.toFile().listFiles(); + if (children.length == 1 && children[0].isDirectory()) { + // make that directory the install path + Path childPath = children[0].toPath(); + Path tmpPath = installPath.getParent().resolve("_t"); //$NON-NLS-1$ + Files.move(childPath, tmpPath); + Files.delete(installPath); + Files.move(tmpPath, installPath); + } + return Status.OK_STATUS; + } catch (IOException | CompressorException | ArchiveException e) { + error = e; + // retry } - return Status.OK_STATUS; - } catch (IOException | CompressorException | ArchiveException e) { - return new Status(IStatus.ERROR, Activator.getId(), "Installing Platform", e); } + // out of retries + return new Status(IStatus.ERROR, Activator.getId(), "Download failed, please try again.", error); } private static Set toPerms(int mode) { diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java index 903933b9f3e..b3fac364591 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java @@ -31,7 +31,6 @@ import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; @@ -225,23 +224,11 @@ public class ArduinoPlatform { return Status.OK_STATUS; } - // Download platform archive - IStatus status = ArduinoManager.downloadAndInstall(url, archiveFileName, getInstallPath(), monitor); - if (!status.isOK()) { - return status; - } - // Install the tools - MultiStatus mstatus = null; for (ToolDependency toolDep : toolsDependencies) { - status = toolDep.install(monitor); + IStatus status = toolDep.install(monitor); if (!status.isOK()) { - if (mstatus == null) { - mstatus = new MultiStatus(status.getPlugin(), status.getCode(), status.getMessage(), - status.getException()); - } else { - mstatus.add(status); - } + return status; } } @@ -256,14 +243,20 @@ public class ArduinoPlatform { makePath.toFile().setExecutable(true, false); } } catch (IOException e) { - mstatus.add(new Status(IStatus.ERROR, Activator.getId(), "downloading make.exe", e)); //$NON-NLS-1$ + return new Status(IStatus.ERROR, Activator.getId(), "Download failed, please try again.", e); } } + // Download platform archive + IStatus status = ArduinoManager.downloadAndInstall(url, archiveFileName, getInstallPath(), monitor); + if (!status.isOK()) { + return status; + } + // Reload the library index to pick up platform libraries ArduinoManager.instance.loadLibraryIndex(false); - return mstatus != null ? mstatus : Status.OK_STATUS; + return Status.OK_STATUS; } @Override diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java index 65680e8fbe5..f6ddb310bbd 100644 --- a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java +++ b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java @@ -7,12 +7,15 @@ *******************************************************************************/ package org.eclipse.cdt.arduino.ui.internal.preferences; +import java.io.File; +import java.io.IOException; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; +import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences; import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard; import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager; import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform; @@ -23,6 +26,7 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.preference.PreferencePage; import org.eclipse.jface.viewers.ColumnWeightData; @@ -178,6 +182,24 @@ public class ArduinoBoardsPreferencePage extends PreferencePage implements IWork @Override public boolean performOk() { + File acceptedFile = ArduinoPreferences.getArduinoHome().resolve(".accepted").toFile(); //$NON-NLS-1$ + if (!acceptedFile.exists()) { + String message = "Do you accept the licenses for the Arduino SDK and libraries? " + + "Information on the licenses can be found at arduino.cc web site."; + MessageDialog dialog = new MessageDialog(getShell(), "Arduino License", null, message, + MessageDialog.QUESTION, new String[] { "Accept", "Decline" }, 0); + int rc = dialog.open(); + if (rc == 0) { + try { + acceptedFile.createNewFile(); + } catch (IOException e) { + Activator.log(e); + } + } else { + return false; + } + } + new Job("Installing Arduino Board Platforms") { @Override protected IStatus run(IProgressMonitor monitor) {