Merge change 3141 into donut
* changes: SDK Updater: Unzip archives.
This commit is contained in:
@@ -54,10 +54,16 @@ public interface ITaskMonitor {
|
|||||||
*/
|
*/
|
||||||
public void incProgress(int delta);
|
public void incProgress(int delta);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current value of the progress bar,
|
||||||
|
* between 0 and up to {@link #setProgressMax(int)} - 1.
|
||||||
|
*/
|
||||||
|
public int getProgress();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the user requested to cancel the operation.
|
* Returns true if the user requested to cancel the operation.
|
||||||
* It is up to the task thread to pool this and exit as soon
|
* It is up to the task thread to pool this and exit as soon
|
||||||
* as possible.
|
* as possible.
|
||||||
*/
|
*/
|
||||||
public boolean cancelRequested();
|
public boolean isCancelRequested();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ public class LocalPackagesPage extends Composite {
|
|||||||
monitor.setProgressMax(100);
|
monitor.setProgressMax(100);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int d = 1;
|
int d = 1;
|
||||||
while(!monitor.cancelRequested()) {
|
while(!monitor.isCancelRequested()) {
|
||||||
monitor.incProgress(d);
|
monitor.incProgress(d);
|
||||||
n += d;
|
n += d;
|
||||||
if (n == 0 || n == 100) d = -d;
|
if (n == 0 || n == 100) d = -d;
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ final class ProgressDialog extends Dialog {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mResultText = new Text(mRootComposite,
|
mResultText = new Text(mRootComposite,
|
||||||
SWT.BORDER | SWT.READ_ONLY | SWT.V_SCROLL | SWT.MULTI);
|
SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
|
||||||
mResultText.setEditable(true);
|
mResultText.setEditable(true);
|
||||||
mResultText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
|
mResultText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
|
||||||
}
|
}
|
||||||
@@ -286,7 +286,15 @@ final class ProgressDialog extends Dialog {
|
|||||||
public void run() {
|
public void run() {
|
||||||
if (!mResultText.isDisposed()) {
|
if (!mResultText.isDisposed()) {
|
||||||
mResultText.setVisible(true);
|
mResultText.setVisible(true);
|
||||||
mResultText.setText(String.format(resultFormat, args));
|
String newText = String.format(resultFormat, args);
|
||||||
|
String lastText = mResultText.getText();
|
||||||
|
if (lastText != null &&
|
||||||
|
lastText.length() > 0 &&
|
||||||
|
!lastText.endsWith("\n") &&
|
||||||
|
!newText.startsWith("\n")) {
|
||||||
|
mResultText.append("\n");
|
||||||
|
}
|
||||||
|
mResultText.append(newText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -327,6 +335,27 @@ final class ProgressDialog extends Dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current value of the progress bar,
|
||||||
|
* between 0 and up to {@link #setProgressMax(int)} - 1.
|
||||||
|
* This method can be invoked from a non-UI thread.
|
||||||
|
*/
|
||||||
|
public int getProgress() {
|
||||||
|
final int[] result = new int[] { 0 };
|
||||||
|
|
||||||
|
if (!mDialogShell.isDisposed()) {
|
||||||
|
mDialogShell.getDisplay().syncExec(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (!mProgressBar.isDisposed()) {
|
||||||
|
result[0] = mProgressBar.getSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the thread that runs the task.
|
* Starts the thread that runs the task.
|
||||||
* This is deferred till the UI is created.
|
* This is deferred till the UI is created.
|
||||||
|
|||||||
@@ -80,11 +80,21 @@ class ProgressTask implements ITaskMonitor {
|
|||||||
mDialog.incProgress(delta);
|
mDialog.incProgress(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current value of the progress bar,
|
||||||
|
* between 0 and up to {@link #setProgressMax(int)} - 1.
|
||||||
|
*
|
||||||
|
* This method can be invoked from a non-UI thread.
|
||||||
|
*/
|
||||||
|
public int getProgress() {
|
||||||
|
return mDialog.getProgress();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the "Cancel" button was selected.
|
* Returns true if the "Cancel" button was selected.
|
||||||
* It is up to the task thread to pool this and exit.
|
* It is up to the task thread to pool this and exit.
|
||||||
*/
|
*/
|
||||||
public boolean cancelRequested() {
|
public boolean isCancelRequested() {
|
||||||
return mDialog.isCancelRequested();
|
return mDialog.isCancelRequested();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import org.eclipse.swt.widgets.List;
|
|||||||
import org.eclipse.swt.widgets.Shell;
|
import org.eclipse.swt.widgets.Shell;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -51,13 +52,15 @@ import java.net.URL;
|
|||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the private implementation of the UpdateWindow.
|
* This is the private implementation of the UpdateWindow.
|
||||||
*/
|
*/
|
||||||
public class UpdaterWindowImpl {
|
public class UpdaterWindowImpl {
|
||||||
|
|
||||||
private static final int NUM_FETCH_URL_MONITOR_INC = 100;
|
private static final int NUM_MONITOR_INC = 100;
|
||||||
|
|
||||||
/** Internal data shared between the window and its pages. */
|
/** Internal data shared between the window and its pages. */
|
||||||
private final UpdaterData mUpdaterData = new UpdaterData();
|
private final UpdaterData mUpdaterData = new UpdaterData();
|
||||||
@@ -338,49 +341,66 @@ public class UpdaterWindowImpl {
|
|||||||
* @param archives The archives to install. Incompatible ones will be skipped.
|
* @param archives The archives to install. Incompatible ones will be skipped.
|
||||||
*/
|
*/
|
||||||
public void installArchives(final Collection<Archive> archives) {
|
public void installArchives(final Collection<Archive> archives) {
|
||||||
|
|
||||||
|
// TODO filter the archive list to: a/ display a list of what is going to be installed,
|
||||||
|
// b/ display licenses and c/ check that the selected packages are actually upgrades
|
||||||
|
// or ask user to confirm downgrades. All this should be done in a separate class+window
|
||||||
|
// which will then call this method with the final list.
|
||||||
|
|
||||||
// TODO move most parts to SdkLib, maybe as part of Archive, making archives self-installing.
|
// TODO move most parts to SdkLib, maybe as part of Archive, making archives self-installing.
|
||||||
mTaskFactory.start("Installing Archives", new ITask() {
|
mTaskFactory.start("Installing Archives", new ITask() {
|
||||||
public void run(ITaskMonitor monitor) {
|
public void run(ITaskMonitor monitor) {
|
||||||
|
|
||||||
monitor.setProgressMax(archives.size() * (NUM_FETCH_URL_MONITOR_INC + 10));
|
final int progressPerArchive = 2 * NUM_MONITOR_INC + 10;
|
||||||
|
monitor.setProgressMax(archives.size() * progressPerArchive);
|
||||||
monitor.setDescription("Preparing to install archives");
|
monitor.setDescription("Preparing to install archives");
|
||||||
|
|
||||||
int num_installed = 0;
|
int numInstalled = 0;
|
||||||
for (Archive archive : archives) {
|
for (Archive archive : archives) {
|
||||||
|
|
||||||
if (!archive.isCompatible()) {
|
int nextProgress = monitor.getProgress() + progressPerArchive;
|
||||||
monitor.setResult("Skipping incompatible archive: %1$s",
|
|
||||||
archive.getParentPackage().getShortDescription());
|
|
||||||
monitor.incProgress(NUM_FETCH_URL_MONITOR_INC + 10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
File archiveFile = null;
|
File archiveFile = null;
|
||||||
try {
|
try {
|
||||||
|
if (monitor.isCancelRequested()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = archive.getParentPackage().getShortDescription();
|
||||||
|
|
||||||
|
// TODO: we should not see this test fail if we had the filter UI above.
|
||||||
|
if (!archive.isCompatible()) {
|
||||||
|
monitor.setResult("Skipping incompatible archive: %1$s", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
archiveFile = downloadArchive(archive, monitor);
|
archiveFile = downloadArchive(archive, monitor);
|
||||||
if (archiveFile != null) {
|
if (archiveFile != null) {
|
||||||
if (installArchive(archive, archiveFile, monitor)) {
|
if (installArchive(archive, archiveFile, monitor)) {
|
||||||
monitor.setResult("Installed: %1$s",
|
monitor.setResult("Installed: %1$s", name);
|
||||||
archive.getParentPackage().getShortDescription());
|
numInstalled++;
|
||||||
num_installed++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
monitor.incProgress(10);
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
// Display anything unexpected in the monitor.
|
// Display anything unexpected in the monitor.
|
||||||
monitor.setResult("Unexpected Error: %1$s", t.getMessage());
|
monitor.setResult("Unexpected Error: %1$s", t.getMessage());
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (archiveFile != null) {
|
// Delete the temp archive if it exists
|
||||||
if (!archiveFile.delete()) {
|
deleteFileOrFolder(archiveFile);
|
||||||
archiveFile.deleteOnExit();
|
|
||||||
}
|
// Always move the progress bar to the desired position.
|
||||||
}
|
// This allows internal methods to not have to care in case
|
||||||
|
// they abort early
|
||||||
|
monitor.incProgress(nextProgress - monitor.getProgress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_installed == 0) {
|
if (numInstalled == 0) {
|
||||||
monitor.setResult("Nothing was installed.");
|
monitor.setDescription("Done. Nothing was installed.");
|
||||||
|
} else {
|
||||||
|
monitor.setDescription("Done. %1$d %2$s installed.",
|
||||||
|
numInstalled,
|
||||||
|
numInstalled == 1 ? "package" : "packages");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -397,8 +417,9 @@ public class UpdaterWindowImpl {
|
|||||||
File tmpFile = File.createTempFile("sdkupload", ".bin"); //$NON-NLS-1$ //$NON-NLS-2$
|
File tmpFile = File.createTempFile("sdkupload", ".bin"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
tmpFileToDelete = tmpFile;
|
tmpFileToDelete = tmpFile;
|
||||||
|
|
||||||
monitor.setDescription("Downloading %1$s",
|
String name = archive.getParentPackage().getShortDescription();
|
||||||
archive.getParentPackage().getShortDescription());
|
String desc = String.format("Downloading %1$s", name);
|
||||||
|
monitor.setDescription(desc);
|
||||||
|
|
||||||
String link = archive.getUrl();
|
String link = archive.getUrl();
|
||||||
if (!link.startsWith("http://") //$NON-NLS-1$
|
if (!link.startsWith("http://") //$NON-NLS-1$
|
||||||
@@ -408,8 +429,7 @@ public class UpdaterWindowImpl {
|
|||||||
Package pkg = archive.getParentPackage();
|
Package pkg = archive.getParentPackage();
|
||||||
RepoSource src = pkg.getParentSource();
|
RepoSource src = pkg.getParentSource();
|
||||||
if (src == null) {
|
if (src == null) {
|
||||||
monitor.setResult("Internal error: no source for archive %1$s",
|
monitor.setResult("Internal error: no source for archive %1$s", name);
|
||||||
archive.getShortDescription());
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +442,7 @@ public class UpdaterWindowImpl {
|
|||||||
link = base + link;
|
link = base + link;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fetchUrl(tmpFile, archive, link, monitor)) {
|
if (fetchUrl(tmpFile, archive, link, desc, monitor)) {
|
||||||
// Fetching was successful, don't delete the temp file here!
|
// Fetching was successful, don't delete the temp file here!
|
||||||
tmpFileToDelete = null;
|
tmpFileToDelete = null;
|
||||||
return tmpFile;
|
return tmpFile;
|
||||||
@@ -432,11 +452,7 @@ public class UpdaterWindowImpl {
|
|||||||
monitor.setResult(e.getMessage());
|
monitor.setResult(e.getMessage());
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (tmpFileToDelete != null) {
|
deleteFileOrFolder(tmpFileToDelete);
|
||||||
if (!tmpFileToDelete.delete()) {
|
|
||||||
tmpFileToDelete.deleteOnExit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -448,11 +464,17 @@ public class UpdaterWindowImpl {
|
|||||||
* Success is defined as downloading as many bytes as was expected and having the same
|
* Success is defined as downloading as many bytes as was expected and having the same
|
||||||
* SHA1 as expected. Returns true on success or false if any of those checks fail.
|
* SHA1 as expected. Returns true on success or false if any of those checks fail.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Increments the monitor by {@link #NUM_FETCH_URL_MONITOR_INC} (which is 10).
|
* Increments the monitor by {@link #NUM_MONITOR_INC}.
|
||||||
*/
|
*/
|
||||||
private boolean fetchUrl(File tmpFile, Archive archive, String urlString, ITaskMonitor monitor) {
|
private boolean fetchUrl(File tmpFile,
|
||||||
|
Archive archive,
|
||||||
|
String urlString,
|
||||||
|
String description,
|
||||||
|
ITaskMonitor monitor) {
|
||||||
URL url;
|
URL url;
|
||||||
|
|
||||||
|
description += " (%1$d%%, %2$.0f KiB/s, %3$d %4$s left)";
|
||||||
|
|
||||||
FileOutputStream os = null;
|
FileOutputStream os = null;
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
try {
|
try {
|
||||||
@@ -467,22 +489,49 @@ public class UpdaterWindowImpl {
|
|||||||
|
|
||||||
long total = 0;
|
long total = 0;
|
||||||
long size = archive.getSize();
|
long size = archive.getSize();
|
||||||
long inc = size / NUM_FETCH_URL_MONITOR_INC;
|
long inc = size / NUM_MONITOR_INC;
|
||||||
long next_inc = inc;
|
long next_inc = inc;
|
||||||
|
|
||||||
|
long startMs = System.currentTimeMillis();
|
||||||
|
long nextMs = startMs + 2000; // start update after 2 seconds
|
||||||
|
|
||||||
while ((n = is.read(buf)) >= 0) {
|
while ((n = is.read(buf)) >= 0) {
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
os.write(buf, 0, n);
|
os.write(buf, 0, n);
|
||||||
digester.update(buf, 0, n);
|
digester.update(buf, 0, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long timeMs = System.currentTimeMillis();
|
||||||
|
|
||||||
total += n;
|
total += n;
|
||||||
if (total >= next_inc) {
|
if (total >= next_inc) {
|
||||||
monitor.incProgress(1);
|
monitor.incProgress(1);
|
||||||
next_inc += inc;
|
next_inc += inc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (monitor.cancelRequested()) {
|
if (timeMs > nextMs) {
|
||||||
|
long delta = timeMs - startMs;
|
||||||
|
if (total > 0 && delta > 0) {
|
||||||
|
// percent left to download
|
||||||
|
int percent = (int) (100 * total / size);
|
||||||
|
// speed in KiB/s
|
||||||
|
float speed = (float)total / (float)delta * (1000.f / 1024.f);
|
||||||
|
// time left to download the rest at the current KiB/s rate
|
||||||
|
int timeLeft = (speed > 1e-3) ?
|
||||||
|
(int)(((size - total) / 1024.0f) / speed) :
|
||||||
|
0;
|
||||||
|
String timeUnit = "seconds";
|
||||||
|
if (timeLeft > 120) {
|
||||||
|
timeUnit = "minutes";
|
||||||
|
timeLeft /= 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor.setDescription(description, percent, speed, timeLeft, timeUnit);
|
||||||
|
}
|
||||||
|
nextMs = timeMs + 1000; // update every second
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor.isCancelRequested()) {
|
||||||
monitor.setResult("Download aborted by user at %1$d bytes.", total);
|
monitor.setResult("Download aborted by user at %1$d bytes.", total);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -540,14 +589,234 @@ public class UpdaterWindowImpl {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the given archive in the given folder.
|
||||||
|
*/
|
||||||
private boolean installArchive(Archive archive, File archiveFile, ITaskMonitor monitor) {
|
private boolean installArchive(Archive archive, File archiveFile, ITaskMonitor monitor) {
|
||||||
monitor.setDescription("Installing %1$s", archive.getShortDescription());
|
String name = archive.getParentPackage().getShortDescription();
|
||||||
|
String desc = String.format("Installing %1$s", name);
|
||||||
|
monitor.setDescription(desc);
|
||||||
|
|
||||||
File destFolder = archive.getParentPackage().getInstallFolder(mUpdaterData.getOsSdkRoot());
|
File destFolder = archive.getParentPackage().getInstallFolder(mUpdaterData.getOsSdkRoot());
|
||||||
|
|
||||||
|
File unzipDestFolder = destFolder;
|
||||||
|
File renamedDestFolder = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// If this folder already exists, unzip in a temporary folder and then move/unlink.
|
||||||
|
if (destFolder.exists()) {
|
||||||
|
// Find a new temp folder that doesn't exist yet
|
||||||
|
unzipDestFolder = findTempFolder(destFolder, "new"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
if (unzipDestFolder == null) {
|
||||||
|
// this should not seriously happen.
|
||||||
|
monitor.setResult("Failed to find a suitable temp directory similar to %1$s.",
|
||||||
|
destFolder.getPath());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unzipDestFolder.mkdirs()) {
|
||||||
|
monitor.setResult("Failed to create temp directory %1$s",
|
||||||
|
unzipDestFolder.getPath());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unzipFolder(archiveFile, archive.getSize(), unzipDestFolder, desc, monitor)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unzipDestFolder != destFolder) {
|
||||||
|
// Swap the old folder by the new one.
|
||||||
|
// Both original folders will be deleted in the finally clause below.
|
||||||
|
renamedDestFolder = findTempFolder(destFolder, "old"); //$NON-NLS-1$
|
||||||
|
if (renamedDestFolder == null) {
|
||||||
|
// this should not seriously happen.
|
||||||
|
monitor.setResult("Failed to find a suitable temp directory similar to %1$s.",
|
||||||
|
destFolder.getPath());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!destFolder.renameTo(renamedDestFolder)) {
|
||||||
|
monitor.setResult("Failed to rename directory %1$s to %2$s",
|
||||||
|
destFolder.getPath(), renamedDestFolder.getPath());
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!unzipDestFolder.renameTo(destFolder)) {
|
||||||
|
monitor.setResult("Failed to rename directory %1$s to %2$s",
|
||||||
|
unzipDestFolder.getPath(), destFolder.getPath());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// Cleanup if the unzip folder is still set.
|
||||||
|
deleteFileOrFolder(renamedDestFolder);
|
||||||
|
if (unzipDestFolder != destFolder) {
|
||||||
|
deleteFileOrFolder(unzipDestFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean unzipFolder(File archiveFile,
|
||||||
|
long compressedSize,
|
||||||
|
File unzipDestFolder,
|
||||||
|
String description,
|
||||||
|
ITaskMonitor monitor) {
|
||||||
|
|
||||||
|
description += " (%1$d%%)";
|
||||||
|
|
||||||
|
FileInputStream fis = null;
|
||||||
|
ZipInputStream zis = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(archiveFile);
|
||||||
|
zis = new ZipInputStream(fis);
|
||||||
|
|
||||||
|
// To advance the percent and the progress bar, we don't know the number of
|
||||||
|
// items left to unzip. However we know the size of the archive and the size of
|
||||||
|
// each uncompressed item. The zip file format overhead is negligible so that's
|
||||||
|
// a good approximation.
|
||||||
|
long incStep = compressedSize / NUM_MONITOR_INC;
|
||||||
|
long incTotal = 0;
|
||||||
|
long incCurr = 0;
|
||||||
|
int lastPercent = 0;
|
||||||
|
|
||||||
|
byte[] buf = new byte[65536];
|
||||||
|
|
||||||
|
ZipEntry entry;
|
||||||
|
while ((entry = zis.getNextEntry()) != null) {
|
||||||
|
|
||||||
|
String name = entry.getName();
|
||||||
|
|
||||||
|
// ZipFile entries should have forward slashes, but not all Zip
|
||||||
|
// implementations can be expected to do that.
|
||||||
|
name = name.replace('\\', '/');
|
||||||
|
|
||||||
|
File destFile = new File(unzipDestFolder, name);
|
||||||
|
|
||||||
|
if (name.endsWith("/")) { //$NON-NLS-1$
|
||||||
|
// Create directory if it doesn't exist yet. This allows us to create
|
||||||
|
// empty directories.
|
||||||
|
if (!destFile.isDirectory() && !destFile.mkdirs()) {
|
||||||
|
monitor.setResult("Failed to create temp directory %1$s",
|
||||||
|
destFile.getPath());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (name.indexOf('/') != -1) {
|
||||||
|
// Otherwise it's a file in a sub-directory.
|
||||||
|
// Make sure the parent directory has been created.
|
||||||
|
File parentDir = destFile.getParentFile();
|
||||||
|
if (!parentDir.isDirectory()) {
|
||||||
|
if (!parentDir.mkdirs()) {
|
||||||
|
monitor.setResult("Failed to create temp directory %1$s",
|
||||||
|
parentDir.getPath());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream(destFile);
|
||||||
|
int n;
|
||||||
|
while ((n = zis.read(buf)) != -1) {
|
||||||
|
if (n > 0) {
|
||||||
|
fos.write(buf, 0, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (fos != null) {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment progress bar to match. We update only between files.
|
||||||
|
for(incTotal += entry.getCompressedSize(); incCurr < incTotal; incCurr += incStep) {
|
||||||
|
monitor.incProgress(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int percent = (int) (100 * incTotal / compressedSize);
|
||||||
|
if (percent != lastPercent) {
|
||||||
|
monitor.setDescription(description, percent);
|
||||||
|
lastPercent = percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor.isCancelRequested()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
monitor.setResult("Unzip failed: %1$s", e.getMessage());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (zis != null) {
|
||||||
|
try {
|
||||||
|
zis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fis != null) {
|
||||||
|
try {
|
||||||
|
fis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a temp folder which name is similar to the one of the ideal folder
|
||||||
|
* and with a ".tmpN" appended.
|
||||||
|
* <p/>
|
||||||
|
* This operation is not atomic so there's no guarantee the folder can't get
|
||||||
|
* created in between. This is however unlikely and the caller can assume the
|
||||||
|
* returned folder does not exist yet.
|
||||||
|
* <p/>
|
||||||
|
* Returns null if no such folder can be found (e.g. if all candidates exist),
|
||||||
|
* which is rather unlikely.
|
||||||
|
*/
|
||||||
|
private File findTempFolder(File idealFolder, String suffix) {
|
||||||
|
String basePath = idealFolder.getPath();
|
||||||
|
|
||||||
|
for (int i = 1; i < 100; i++) {
|
||||||
|
File folder = new File(String.format("%1$s.%2$s%3$02d", basePath, suffix, i)); //$NON-NLS-1$
|
||||||
|
if (!folder.exists()) {
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a file or a directory.
|
||||||
|
* Directories are deleted recursively.
|
||||||
|
* The argument can be null.
|
||||||
|
*/
|
||||||
|
private void deleteFileOrFolder(File fileOrFolder) {
|
||||||
|
if (fileOrFolder != null) {
|
||||||
|
if (fileOrFolder.isDirectory()) {
|
||||||
|
// Must delete content recursively first
|
||||||
|
for (File item : fileOrFolder.listFiles()) {
|
||||||
|
deleteFileOrFolder(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fileOrFolder.delete()) {
|
||||||
|
fileOrFolder.deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// End of hiding from SWT Designer
|
// End of hiding from SWT Designer
|
||||||
//$hide<<$
|
//$hide<<$
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user