From 9be7c5b71223ac6db32c99b2d2bddfb44b4d3b2b Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 8 Jun 2009 23:40:29 -0700 Subject: [PATCH] SDK Updater: Support local archives - Change Archive to have a "isLocal" mode. - In local mode, Archive.getLocalOsPath gives the install folder. - In remote mode, Archive.getUrl gives the download URL. - Implement delete on local archive. - Started refreshing all sources. Need to revamp the progress dialog to share it accross methods first. --- .../internal/repository/AddonPackage.java | 7 +- .../sdklib/internal/repository/Archive.java | 58 +++++++++- .../internal/repository/DocPackage.java | 11 +- .../internal/repository/LocalSdkParser.java | 18 +--- .../sdklib/internal/repository/Package.java | 11 +- .../internal/repository/PlatformPackage.java | 7 +- .../internal/repository/ToolPackage.java | 11 +- .../repository/LocalPackagesPage.java | 100 ++++++++++++++---- .../repository/RemotePackagesPage.java | 34 +++++- .../repository/UpdaterWindowImpl.java | 53 +++++++++- 10 files changed, 238 insertions(+), 72 deletions(-) diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java index 0c666d295..f204ba5a0 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java @@ -76,7 +76,8 @@ public class AddonPackage extends Package { /** * Creates a new platform package based on an actual {@link IAndroidTarget} (which * {@link IAndroidTarget#isPlatform()} false) from the {@link SdkManager}. - * This is used to list local SDK folders. + * This is used to list local SDK folders in which case there is one archive which + * URL is the actual target location. */ AddonPackage(IAndroidTarget target) { super( null, //source @@ -86,9 +87,7 @@ public class AddonPackage extends Package { null, //descUrl Os.getCurrentOs(), //archiveOs Arch.getCurrentArch(), //archiveArch - "", //archiveUrl //$NON-NLS-1$ - 0, //archiveSize - null //archiveChecksum + target.getLocation() //archiveOsPath ); mApiLevel = target.getApiVersionNumber(); diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java index a67d6b212..715311a23 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java @@ -154,17 +154,43 @@ public class Archive implements IDescription { private final String mChecksum; private final ChecksumType mChecksumType = ChecksumType.SHA1; private final Package mPackage; + private final String mLocalOsPath; + private final boolean mIsLocal; /** - * Creates a new archive. + * Creates a new remote archive. */ Archive(Package pkg, Os os, Arch arch, String url, long size, String checksum) { mPackage = pkg; mOs = os; mArch = arch; mUrl = url; + mLocalOsPath = null; mSize = size; mChecksum = checksum; + mIsLocal = false; + } + + /** + * Creates a new local archive. + */ + Archive(Package pkg, Os os, Arch arch, String localOsPath) { + mPackage = pkg; + mOs = os; + mArch = arch; + mUrl = null; + mLocalOsPath = localOsPath; + mSize = 0; + mChecksum = ""; + mIsLocal = true; + } + + /** + * Returns true if this is a locally installed archive. + * Returns false if this is a remote archive that needs to be downloaded. + */ + public boolean isLocal() { + return mIsLocal; } /** @@ -200,12 +226,22 @@ public class Archive implements IDescription { /** * Returns the download archive URL, either absolute or relative to the repository xml. - * For a local installed folder, an URL is frabricated from the folder path. + * Always return null for a local installed folder. + * @see #getLocalOsPath() */ public String getUrl() { return mUrl; } + /** + * Returns the local OS folder where a local archive is installed. + * Always return null for remote archives. + * @see #getUrl() + */ + public String getLocalOsPath() { + return mLocalOsPath; + } + /** * Returns the archive {@link Os} enum. * Can be null for a local installed folder on an unknown OS. @@ -290,6 +326,15 @@ public class Archive implements IDescription { return true; } + /** + * Delete the archive folder if this is a local archive. + */ + public void deleteLocal() { + if (isLocal()) { + deleteFileOrFolder(new File(getLocalOsPath())); + } + } + /** * Install this {@link Archive}s. * The archive will be skipped if it is incompatible. @@ -302,7 +347,14 @@ public class Archive implements IDescription { try { String name = getParentPackage().getShortDescription(); - // TODO: we should not see this test fail if we had the filter UI above. + if (isLocal()) { + // This should never happen. + monitor.setResult("Skipping already installed archive: %1$s for %2$s", + name, + getOsDescription()); + return false; + } + if (!isCompatible()) { monitor.setResult("Skipping incompatible archive: %1$s for %2$s", name, diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java index e2c2cf5f9..4770765b6 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java @@ -44,7 +44,8 @@ public class DocPackage extends Package { /** * Manually create a new package with one archive and the given attributes. - * This is used to create packages from local directories. + * This is used to create packages from local directories in which case there must be + * one archive which URL is the actual target location. */ DocPackage(RepoSource source, int apiLevel, @@ -54,9 +55,7 @@ public class DocPackage extends Package { String descUrl, Os archiveOs, Arch archiveArch, - String archiveUrl, - long archiveSize, - String archiveChecksum) { + String archiveOsPath) { super(source, revision, license, @@ -64,9 +63,7 @@ public class DocPackage extends Package { descUrl, archiveOs, archiveArch, - archiveUrl, - archiveSize, - archiveChecksum); + archiveOsPath); mApiLevel = apiLevel; } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java index 8d067f267..d52cce658 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java @@ -35,7 +35,6 @@ import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; -import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; @@ -60,7 +59,7 @@ public class LocalSdkParser { private Package[] mPackages; public LocalSdkParser() { - // TODO Auto-generated constructor stub + // pass } /** @@ -172,9 +171,7 @@ public class LocalSdkParser { null, //descUrl Os.getCurrentOs(), //archiveOs Arch.getCurrentArch(), //archiveArch - "", //archiveUrl //$NON-NLS-1$ - 0, //archiveSize - null //archiveChecksum + toolFolder.getPath() //archiveOsPath ); } @@ -219,13 +216,6 @@ public class LocalSdkParser { // Create a pkg if we don't have one yet. if (pkg == null) { - String url = null; - try { - url = docFolder.toURI().toURL().toString(); - } catch (MalformedURLException e) { - // ignore - } - pkg = new DocPackage( null, //source 0, //apiLevel @@ -235,9 +225,7 @@ public class LocalSdkParser { null, //descUrl Os.getCurrentOs(), //archiveOs Arch.getCurrentArch(), //archiveArch - url, //archiveUrl - 0, //archiveSize - null //archiveChecksum + docFolder.getPath() //archiveOsPath ); } } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java index 4d28f0895..64ff007ce 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java @@ -62,7 +62,8 @@ public abstract class Package implements IDescription { /** * Manually create a new package with one archive and the given attributes. - * This is used to create packages from local directories. + * This is used to create packages from local directories in which case there must be + * one archive which URL is the actual target location. */ public Package(RepoSource source, int revision, @@ -71,9 +72,7 @@ public abstract class Package implements IDescription { String descUrl, Os archiveOs, Arch archiveArch, - String archiveUrl, - long archiveSize, - String archiveChecksum) { + String archiveOsPath) { mSource = source; mRevision = revision; mLicense = license; @@ -83,9 +82,7 @@ public abstract class Package implements IDescription { mArchives[0] = new Archive(this, archiveOs, archiveArch, - archiveUrl, - archiveSize, - archiveChecksum); + archiveOsPath); } /** diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java index ae6bc77ed..0724e3026 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java @@ -49,7 +49,8 @@ public class PlatformPackage extends Package { /** * Creates a new platform package based on an actual {@link IAndroidTarget} (which * must have {@link IAndroidTarget#isPlatform()} true) from the {@link SdkManager}. - * This is used to list local SDK folders. + * This is used to list local SDK folders in which case there is one archive which + * URL is the actual target location. */ PlatformPackage(IAndroidTarget target) { super( null, //source @@ -59,9 +60,7 @@ public class PlatformPackage extends Package { null, //descUrl Os.getCurrentOs(), //archiveOs Arch.getCurrentArch(), //archiveArch - "", //archiveUrl //$NON-NLS-1$ - 0, //archiveSize - null //archiveChecksum + target.getLocation() //archiveOsPath ); mApiLevel = target.getApiVersionNumber(); diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java index 4cac70614..1b23e8ae3 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java @@ -40,7 +40,8 @@ public class ToolPackage extends Package { /** * Manually create a new package with one archive and the given attributes. - * This is used to create packages from local directories. + * This is used to create packages from local directories in which case there must be + * one archive which URL is the actual target location. */ ToolPackage(RepoSource source, int revision, @@ -49,9 +50,7 @@ public class ToolPackage extends Package { String descUrl, Os archiveOs, Arch archiveArch, - String archiveUrl, - long archiveSize, - String archiveChecksum) { + String archiveOsPath) { super(source, revision, license, @@ -59,9 +58,7 @@ public class ToolPackage extends Package { descUrl, archiveOs, archiveArch, - archiveUrl, - archiveSize, - archiveChecksum); + archiveOsPath); } /** Returns a short description for an {@link IDescription}. */ diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalPackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalPackagesPage.java index abc729ead..4f0700919 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalPackagesPage.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalPackagesPage.java @@ -16,10 +16,13 @@ package com.android.sdkuilib.internal.repository; +import com.android.sdklib.internal.repository.Archive; import com.android.sdklib.internal.repository.IDescription; import com.android.sdklib.internal.repository.ITask; import com.android.sdklib.internal.repository.ITaskMonitor; +import com.android.sdklib.internal.repository.Package; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; @@ -39,6 +42,8 @@ import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.Text; +import java.io.File; + /* * TODO list * - select => update desc, enable update + delete, enable home page if url @@ -49,7 +54,9 @@ import org.eclipse.swt.widgets.Text; */ public class LocalPackagesPage extends Composite { - private UpdaterData mUpdaterData; + + private final UpdaterWindowImpl mUpdaterWindow; + private final UpdaterData mUpdaterData; private Label mSdkLocLabel; private Text mSdkLocText; @@ -63,17 +70,22 @@ public class LocalPackagesPage extends Composite { private Label mPlaceholder1; private Button mDeleteButton; private Label mPlaceholder2; - private Button mHomePageButton; + private Button mRefreshButton; private Label mDescriptionLabel; + /** * Create the composite. * @param parent The parent of the composite. * @param updaterData An instance of {@link UpdaterData}. If null, a local * one will be allocated just to help with the SWT Designer. + * @param updaterWindow The parent window. */ - public LocalPackagesPage(Composite parent, UpdaterData updaterData) { + public LocalPackagesPage(Composite parent, + UpdaterData updaterData, + UpdaterWindowImpl updaterWindow) { super(parent, SWT.BORDER); + mUpdaterWindow = updaterWindow; mUpdaterData = updaterData != null ? updaterData : new UpdaterData(); @@ -127,15 +139,27 @@ public class LocalPackagesPage extends Composite { mPlaceholder1.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); mDeleteButton = new Button(mContainerButtons, SWT.NONE); + mDeleteButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onDeleteSelected(); //$hide$ (hide from SWT designer) + } + }); mDeleteButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1)); mDeleteButton.setText("Delete..."); mPlaceholder2 = new Label(mContainerButtons, SWT.NONE); mPlaceholder2.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); - mHomePageButton = new Button(mContainerButtons, SWT.NONE); - mHomePageButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); - mHomePageButton.setText("Home Page..."); + mRefreshButton = new Button(mContainerButtons, SWT.NONE); + mRefreshButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onRefreshSelected(); //$hide$ (hide from SWT designer) + } + }); + mRefreshButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + mRefreshButton.setText("Refresh"); } private void createSdkLocation(Composite parent) { @@ -225,25 +249,57 @@ public class LocalPackagesPage extends Composite { } private void onUpdateInstalledPackage() { - // TODO just a test, needs to be removed later. - new ProgressTask(getShell(), "Test", new ITask() { - public void run(ITaskMonitor monitor) { - monitor.setDescription("Test"); - monitor.setProgressMax(100); - int n = 0; - int d = 1; - while(!monitor.isCancelRequested()) { - monitor.incProgress(d); - n += d; - if (n == 0 || n == 100) d = -d; - try { - Thread.sleep(5); - } catch (InterruptedException e) { - // ignore + if (mUpdaterWindow != null) { + mUpdaterWindow.updateAll(); + } + } + + private void onDeleteSelected() { + ISelection sel = mTableViewerPackages.getSelection(); + if (sel instanceof IStructuredSelection) { + Object elem = ((IStructuredSelection) sel).getFirstElement(); + if (elem instanceof Package) { + + String title = "Delete SDK Package"; + String error = null; + + Package p = (Package) elem; + Archive[] archives = p.getArchives(); + if (archives.length == 1 && archives[0] != null && archives[0].isLocal()) { + Archive archive = archives[0]; + String osPath = archive.getLocalOsPath(); + + File dir = new File(osPath); + if (dir.isDirectory()) { + String msg = String.format("Are you sure you want to delete '%1$s' at '%2$s'? This cannot be undone.", + p.getShortDescription(), osPath); + + if (MessageDialog.openQuestion(getShell(), title, msg)) { + archive.deleteLocal(); + + // refresh list + onRefreshSelected(); + } + } else { + error = "Directory not found for this package"; } + } else { + error = "No local archive found for this package"; } + + if (error != null) { + MessageDialog.openError(getShell(), title, error); + } + + return; } - }); + } + } + + private void onRefreshSelected() { + if (mUpdaterWindow != null) { + mUpdaterWindow.scanLocalSdkFolders(); + } } // End of hiding from SWT Designer diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java index 1fe5ca42b..6cc11a349 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java @@ -131,15 +131,33 @@ public class RemotePackagesPage extends Composite { mDescriptionLabel.setText("Line1\nLine2\nLine3"); mAddSiteButton = new Button(parent, SWT.NONE); + mAddSiteButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onAddSiteSelected(); //$hide$ + } + }); mAddSiteButton.setText("Add Site..."); mRemoveSiteButton = new Button(parent, SWT.NONE); + mRemoveSiteButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onRemoveSiteSelected(); //$hide$ + } + }); mRemoveSiteButton.setText("Delete Site..."); mPlaceholder3 = new Label(parent, SWT.NONE); mPlaceholder3.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1)); mRefreshButton = new Button(parent, SWT.NONE); + mRefreshButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onRefreshSelected(); //$hide$ + } + }); mRefreshButton.setText("Refresh"); mInstallSelectedButton = new Button(parent, SWT.NONE); @@ -234,7 +252,21 @@ public class RemotePackagesPage extends Composite { } } - mUpdaterWindow.installArchives(archives); + if (mUpdaterWindow != null) { + mUpdaterWindow.installArchives(archives); + } + } + + private void onAddSiteSelected() { + } + + private void onRemoveSiteSelected() { + } + + private void onRefreshSelected() { + if (mUpdaterWindow != null) { + mUpdaterWindow.refreshSources(false /*forceFetching*/); + } } // End of hiding from SWT Designer diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java index e4d15f53c..4dc9761ac 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java @@ -23,6 +23,7 @@ import com.android.sdklib.internal.repository.Archive; import com.android.sdklib.internal.repository.ITask; import com.android.sdklib.internal.repository.ITaskMonitor; import com.android.sdklib.internal.repository.RepoSource; +import com.android.sdklib.internal.repository.RepoSources; import com.android.sdklib.repository.SdkRepository; import org.eclipse.swt.SWT; @@ -136,7 +137,7 @@ public class UpdaterWindowImpl { mStackLayout = new StackLayout(); mPagesRootComposite.setLayout(mStackLayout); - mLocalPackagePage = new LocalPackagesPage(mPagesRootComposite, mUpdaterData); + mLocalPackagePage = new LocalPackagesPage(mPagesRootComposite, mUpdaterData, this); mRemotePackagesPage = new RemotePackagesPage(mPagesRootComposite, mUpdaterData, this); mSashForm.setWeights(new int[] {150, 576}); } @@ -327,7 +328,7 @@ public class UpdaterWindowImpl { /** * Used to scan the local SDK folders the first time. */ - private void scanLocalSdkFolders() { + public void scanLocalSdkFolders() { mUpdaterData.getLocalSdkAdapter().setSdkRoot(mUpdaterData.getOsSdkRoot()); mLocalPackagePage.setInput(mUpdaterData.getLocalSdkAdapter()); @@ -389,6 +390,54 @@ public class UpdaterWindowImpl { }); } + public void updateAll() { + refreshSources(true); + + // TODO have refreshSources reuse the current progress task +// mTaskFactory.start("Update Archives", new ITask() { +// public void run(ITaskMonitor monitor) { +// monitor.setProgressMax(3); +// +// monitor.setDescription("Refresh sources"); +// refreshSources(true); +// } +// }); + } + + /** + * Refresh sources + * + * @param forceFetching When true, load sources that haven't been loaded yet. When + * false, only refresh sources that have been loaded yet. + */ + public void refreshSources(final boolean forceFetching) { + ArrayList sources = mUpdaterData.getSources().getSources(); + for (RepoSource source : sources) { + if (forceFetching || source.getPackages() != null) { + source.load(mTaskFactory); + } + + } + + // TODO have source.load reuse the current progress task +// mTaskFactory.start("Refresh sources", new ITask() { +// public void run(ITaskMonitor monitor) { +// ArrayList sources = mUpdaterData.getSources().getSources(); +// monitor.setProgressMax(sources.size()); +// +// for (RepoSource source : sources) { +// if (forceFetching || source.getPackages() != null) { +// monitor.setDescription(String.format("Refresh %1$s", +// source.getShortDescription())); +// source.load(mTaskFactory); +// } +// monitor.incProgress(1); +// } +// } +// }); + + } + // End of hiding from SWT Designer //$hide<<$ }