am 630f7df1: Merge change 4575 into donut

Merge commit '630f7df118eb813891752821c239f853ff540a4f'

* commit '630f7df118eb813891752821c239f853ff540a4f':
  SDK Updater: Better guess for the addon folder name.
This commit is contained in:
Android (Google) Code Review
2009-06-18 12:03:58 -07:00
committed by The Android Open Source Project
9 changed files with 149 additions and 77 deletions

View File

@@ -182,25 +182,46 @@ public class AddonPackage extends Package {
* has this add-ons installed, we'll use that one. * has this add-ons installed, we'll use that one.
* *
* @param osSdkRoot The OS path of the SDK root folder. * @param osSdkRoot The OS path of the SDK root folder.
* @param suggestedDir A suggestion for the installation folder name, based on the root
* folder used in the zip archive.
* @param sdkManager An existing SDK manager to list current platforms and addons.
* @return A new {@link File} corresponding to the directory to use to install this package. * @return A new {@link File} corresponding to the directory to use to install this package.
*/ */
@Override @Override
public File getInstallFolder(String osSdkRoot) { public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
File addons = new File(osSdkRoot, SdkConstants.FD_ADDONS); File addons = new File(osSdkRoot, SdkConstants.FD_ADDONS);
String name = String.format("%s-%d", getName(), getApiLevel()); // $NON-NLS-1$ // First find if this add-on is already installed. If so, reuse the same directory.
for (IAndroidTarget target : sdkManager.getTargets()) {
if (!target.isPlatform() &&
target.getApiVersionNumber() == getApiLevel() &&
target.getName().equals(getName()) &&
target.getVendor().equals(getVendor())) {
return new File(target.getLocation());
}
}
// FIXME this will fail if the name is not ASCII compatible. This could easily // Otherwise, see about reusing the suggestedDir. It must not be already used or
// happen: a Chinese or Japanese name etc for example, // add some index to it, or we try to make up one.
// to name a few. String name = suggestedDir;
name = name.toLowerCase();
name = name.replaceAll("[^a-zA-Z0-9_-]+", "_"); // $NON-NLS-1$
name = name.replaceAll("_+", "_"); // $NON-NLS-1$
File folder = new File(addons, name); if (suggestedDir == null || suggestedDir.length() == 0) {
name = String.format("addon-%s-%s-%d", getName(), getVendor(), getApiLevel()); //$NON-NLS-1$
name = name.toLowerCase();
name = name.replaceAll("[^a-z0-9_-]+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
name = name.replaceAll("_+", "_"); //$NON-NLS-1$ //$NON-NLS-2$
}
// TODO find similar existing addon in addons folder for (int i = 0; i < 100; i++) {
return folder; String name2 = i == 0 ? name : String.format("%s-%d", name, i); //$NON-NLS-1$
File folder = new File(addons, name2);
if (!folder.exists()) {
return folder;
}
}
// We shouldn't really get here. I mean, seriously, we tried hard enough.
return null;
} }
/** /**

View File

@@ -16,6 +16,8 @@
package com.android.sdklib.internal.repository; package com.android.sdklib.internal.repository;
import com.android.sdklib.SdkManager;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@@ -341,7 +343,10 @@ public class Archive implements IDescription {
* *
* @return True if the archive was installed, false otherwise. * @return True if the archive was installed, false otherwise.
*/ */
public boolean install(String osSdkRoot, boolean forceHttp, ITaskMonitor monitor) { public boolean install(String osSdkRoot,
boolean forceHttp,
SdkManager sdkManager,
ITaskMonitor monitor) {
File archiveFile = null; File archiveFile = null;
try { try {
@@ -364,7 +369,7 @@ public class Archive implements IDescription {
archiveFile = downloadFile(monitor, forceHttp); archiveFile = downloadFile(monitor, forceHttp);
if (archiveFile != null) { if (archiveFile != null) {
if (unarchive(osSdkRoot, archiveFile, monitor)) { if (unarchive(osSdkRoot, archiveFile, sdkManager, monitor)) {
monitor.setResult("Installed: %1$s", name); monitor.setResult("Installed: %1$s", name);
return true; return true;
} }
@@ -568,48 +573,63 @@ public class Archive implements IDescription {
/** /**
* Install the given archive in the given folder. * Install the given archive in the given folder.
*/ */
private boolean unarchive(String osSdkRoot, File archiveFile, ITaskMonitor monitor) { private boolean unarchive(String osSdkRoot,
String name = getParentPackage().getShortDescription(); File archiveFile,
String desc = String.format("Installing %1$s", name); SdkManager sdkManager,
monitor.setDescription(desc); ITaskMonitor monitor) {
String pkgName = getParentPackage().getShortDescription();
String pkgDesc = String.format("Installing %1$s", pkgName);
monitor.setDescription(pkgDesc);
File destFolder = getParentPackage().getInstallFolder(osSdkRoot); // We always unzip in a temp folder which name depends on the package type
// (e.g. addon, tools, etc.) and then move the folder to the destination folder.
// If the destination folder exists, it will be renamed and deleted at the very
// end if everything succeeded.
File unzipDestFolder = destFolder; String pkgKind = getParentPackage().getClass().getSimpleName();
File destFolder = null;
File unzipDestFolder = null;
File renamedDestFolder = null; File renamedDestFolder = null;
try { try {
// If this folder already exists, unzip in a temporary folder and then move/unlink. // Find a new temp folder that doesn't exist yet
if (destFolder.exists()) { unzipDestFolder = findTempFolder(osSdkRoot, pkgKind, "new"); //$NON-NLS-1$
// Find a new temp folder that doesn't exist yet
unzipDestFolder = findTempFolder(destFolder, "new"); //$NON-NLS-1$
if (unzipDestFolder == null) { if (unzipDestFolder == null) {
// this should not seriously happen. // this should not seriously happen.
monitor.setResult("Failed to find a suitable temp directory similar to %1$s.", monitor.setResult("Failed to find a temp directory in %1$s.", osSdkRoot);
destFolder.getPath()); return false;
return false;
}
} }
if (!unzipDestFolder.mkdirs()) { if (!unzipDestFolder.mkdirs()) {
monitor.setResult("Failed to create directory %1$s", monitor.setResult("Failed to create directory %1$s", unzipDestFolder.getPath());
unzipDestFolder.getPath());
return false; return false;
} }
if (!unzipFolder(archiveFile, getSize(), unzipDestFolder, desc, monitor)) { String[] zipRootFolder = new String[] { null };
if (!unzipFolder(archiveFile, getSize(),
unzipDestFolder, pkgDesc,
zipRootFolder, monitor)) {
return false; return false;
} }
if (unzipDestFolder != destFolder) { // Compute destination directory
// Swap the old folder by the new one. destFolder = getParentPackage().getInstallFolder(
// Both original folders will be deleted in the finally clause below. osSdkRoot, zipRootFolder[0], sdkManager);
renamedDestFolder = findTempFolder(destFolder, "old"); //$NON-NLS-1$
if (destFolder == null) {
// this should not seriously happen.
monitor.setResult("Failed to compute installation directory for %1$s.", pkgName);
return false;
}
// Swap the old folder by the new one.
if (destFolder.isDirectory()) {
renamedDestFolder = findTempFolder(osSdkRoot, pkgKind, "old"); //$NON-NLS-1$
if (renamedDestFolder == null) { if (renamedDestFolder == null) {
// this should not seriously happen. // this should not seriously happen.
monitor.setResult("Failed to find a suitable temp directory similar to %1$s.", monitor.setResult("Failed to find a temp directory in %1$s.", osSdkRoot);
destFolder.getPath());
return false; return false;
} }
@@ -619,28 +639,36 @@ public class Archive implements IDescription {
return false; return false;
} }
if (!unzipDestFolder.renameTo(destFolder)) {
monitor.setResult("Failed to rename directory %1$s to %2$s",
unzipDestFolder.getPath(), destFolder.getPath());
return false;
}
} }
if (!unzipDestFolder.renameTo(destFolder)) {
monitor.setResult("Failed to rename directory %1$s to %2$s",
unzipDestFolder.getPath(), destFolder.getPath());
return false;
}
unzipDestFolder = null;
return true; return true;
} finally { } finally {
// Cleanup if the unzip folder is still set. // Cleanup if the unzip folder is still set.
deleteFileOrFolder(renamedDestFolder); deleteFileOrFolder(renamedDestFolder);
if (unzipDestFolder != destFolder) { deleteFileOrFolder(unzipDestFolder);
deleteFileOrFolder(unzipDestFolder);
}
} }
} }
/**
* Unzips a zip file into the given destination directory.
*
* The archive file MUST have a unique "root" folder. This root folder is skipped when
* unarchiving. However we return that root folder name to the caller, as it can be used
* as a template to know what destination directory to use in the Add-on case.
*/
private boolean unzipFolder(File archiveFile, private boolean unzipFolder(File archiveFile,
long compressedSize, long compressedSize,
File unzipDestFolder, File unzipDestFolder,
String description, String description,
String[] outZipRootFolder,
ITaskMonitor monitor) { ITaskMonitor monitor) {
description += " (%1$d%%)"; description += " (%1$d%%)";
@@ -678,6 +706,9 @@ public class Archive implements IDescription {
if (pos < 0 || pos == name.length() - 1) { if (pos < 0 || pos == name.length() - 1) {
continue; continue;
} else { } else {
if (outZipRootFolder[0] == null && pos > 0) {
outZipRootFolder[0] = name.substring(0, pos);
}
name = name.substring(pos + 1); name = name.substring(pos + 1);
} }
@@ -762,21 +793,27 @@ public class Archive implements IDescription {
} }
/** /**
* Finds a temp folder which name is similar to the one of the ideal folder * Finds a temp folder in the form of osBasePath/temp/prefix.suffixNNN.
* and with a ".tmpN" appended.
* <p/> * <p/>
* This operation is not atomic so there's no guarantee the folder can't get * 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 * created in between. This is however unlikely and the caller can assume the
* returned folder does not exist yet. * returned folder does not exist yet.
* <p/> * <p/>
* Returns null if no such folder can be found (e.g. if all candidates exist), * Returns null if no such folder can be found (e.g. if all candidates exist,
* which is rather unlikely. * which is rather unlikely) or if the base temp folder cannot be created.
*/ */
private File findTempFolder(File idealFolder, String suffix) { private File findTempFolder(String osBasePath, String prefix, String suffix) {
String basePath = idealFolder.getPath(); File baseTempFolder = new File(osBasePath, "temp");
if (!baseTempFolder.isDirectory()) {
if (!baseTempFolder.mkdirs()) {
return null;
}
}
for (int i = 1; i < 100; i++) { 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$ File folder = new File(baseTempFolder,
String.format("%1$s.%2$s%3$02d", prefix, suffix, i)); //$NON-NLS-1$
if (!folder.exists()) { if (!folder.exists()) {
return folder; return folder;
} }

View File

@@ -17,6 +17,7 @@
package com.android.sdklib.internal.repository; package com.android.sdklib.internal.repository;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.repository.Archive.Arch; import com.android.sdklib.internal.repository.Archive.Arch;
import com.android.sdklib.internal.repository.Archive.Os; import com.android.sdklib.internal.repository.Archive.Os;
import com.android.sdklib.repository.SdkRepository; import com.android.sdklib.repository.SdkRepository;
@@ -98,10 +99,13 @@ public class DocPackage extends Package {
* A "doc" package should always be located in SDK/docs. * A "doc" package should always be located in SDK/docs.
* *
* @param osSdkRoot The OS path of the SDK root folder. * @param osSdkRoot The OS path of the SDK root folder.
* @param suggestedDir A suggestion for the installation folder name, based on the root
* folder used in the zip archive.
* @param sdkManager An existing SDK manager to list current platforms and addons.
* @return A new {@link File} corresponding to the directory to use to install this package. * @return A new {@link File} corresponding to the directory to use to install this package.
*/ */
@Override @Override
public File getInstallFolder(String osSdkRoot) { public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
return new File(osSdkRoot, SdkConstants.FD_DOCS); return new File(osSdkRoot, SdkConstants.FD_DOCS);
} }

View File

@@ -17,7 +17,6 @@
package com.android.sdklib.internal.repository; package com.android.sdklib.internal.repository;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager; import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.repository.Archive.Arch; import com.android.sdklib.internal.repository.Archive.Arch;
@@ -63,7 +62,7 @@ public class LocalSdkParser {
} }
/** /**
* Returns the packages found by the last call to {@link #parseSdk(String)}. * Returns the packages found by the last call to {@link #parseSdk(String, SdkManager)}.
*/ */
public Package[] getPackages() { public Package[] getPackages() {
return mPackages; return mPackages;
@@ -71,7 +70,7 @@ public class LocalSdkParser {
/** /**
* Clear the internal packages list. After this call, {@link #getPackages()} will return * Clear the internal packages list. After this call, {@link #getPackages()} will return
* null till {@link #parseSdk(String)} is called. * null till {@link #parseSdk(String, SdkManager)} is called.
*/ */
public void clearPackages() { public void clearPackages() {
mPackages = null; mPackages = null;
@@ -84,9 +83,10 @@ public class LocalSdkParser {
* at any time later. * at any time later.
* *
* @param osSdkRoot The path to the SDK folder. * @param osSdkRoot The path to the SDK folder.
* @param sdkManager An existing SDK manager to list current platforms and addons.
* @return The packages found. Can be retrieved later using {@link #getPackages()}. * @return The packages found. Can be retrieved later using {@link #getPackages()}.
*/ */
public Package[] parseSdk(String osSdkRoot) { public Package[] parseSdk(String osSdkRoot, SdkManager sdkManager) {
ArrayList<Package> packages = new ArrayList<Package>(); ArrayList<Package> packages = new ArrayList<Package>();
Package pkg = scanDoc(new File(osSdkRoot, SdkConstants.FD_DOCS)); Package pkg = scanDoc(new File(osSdkRoot, SdkConstants.FD_DOCS));
@@ -100,20 +100,7 @@ public class LocalSdkParser {
} }
// for platforms and add-ons, rely on the SdkManager parser // for platforms and add-ons, rely on the SdkManager parser
SdkManager sdkman = SdkManager.createManager(osSdkRoot, new ISdkLog() { for(IAndroidTarget target : sdkManager.getTargets()) {
// A dummy sdk logger that doesn't log anything.
public void error(Throwable t, String errorFormat, Object... args) {
// pass
}
public void printf(String msgFormat, Object... args) {
// pass
}
public void warning(String warningFormat, Object... args) {
// pass
}
});
for(IAndroidTarget target : sdkman.getTargets()) {
pkg = null; pkg = null;
if (target.isPlatform()) { if (target.isPlatform()) {

View File

@@ -16,6 +16,7 @@
package com.android.sdklib.internal.repository; package com.android.sdklib.internal.repository;
import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.repository.Archive.Arch; import com.android.sdklib.internal.repository.Archive.Arch;
import com.android.sdklib.internal.repository.Archive.Os; import com.android.sdklib.internal.repository.Archive.Os;
import com.android.sdklib.repository.SdkRepository; import com.android.sdklib.repository.SdkRepository;
@@ -198,9 +199,13 @@ public abstract class Package implements IDescription {
* existing or new folder depending on the current content of the SDK. * existing or new folder depending on the current content of the SDK.
* *
* @param osSdkRoot The OS path of the SDK root folder. * @param osSdkRoot The OS path of the SDK root folder.
* @param suggestedDir A suggestion for the installation folder name, based on the root
* folder used in the zip archive.
* @param sdkManager An existing SDK manager to list current platforms and addons.
* @return A new {@link File} corresponding to the directory to use to install this package. * @return A new {@link File} corresponding to the directory to use to install this package.
*/ */
public abstract File getInstallFolder(String osSdkRoot); public abstract File getInstallFolder(
String osSdkRoot, String suggestedDir, SdkManager sdkManager);
/** /**
* Computes whether the given package is a suitable update for the current package. * Computes whether the given package is a suitable update for the current package.

View File

@@ -102,10 +102,23 @@ public class PlatformPackage extends Package {
* has this platform version installed, we'll use that one. * has this platform version installed, we'll use that one.
* *
* @param osSdkRoot The OS path of the SDK root folder. * @param osSdkRoot The OS path of the SDK root folder.
* @param suggestedDir A suggestion for the installation folder name, based on the root
* folder used in the zip archive.
* @param sdkManager An existing SDK manager to list current platforms and addons.
* @return A new {@link File} corresponding to the directory to use to install this package. * @return A new {@link File} corresponding to the directory to use to install this package.
*/ */
@Override @Override
public File getInstallFolder(String osSdkRoot) { public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
// First find if this add-on is already installed. If so, reuse the same directory.
for (IAndroidTarget target : sdkManager.getTargets()) {
if (target.isPlatform() &&
target.getApiVersionNumber() == getApiLevel() &&
target.getApiVersionName().equals(getVersion())) {
return new File(target.getLocation());
}
}
File platforms = new File(osSdkRoot, SdkConstants.FD_PLATFORMS); File platforms = new File(osSdkRoot, SdkConstants.FD_PLATFORMS);
File folder = new File(platforms, String.format("android-%s", getVersion())); //$NON-NLS-1$ File folder = new File(platforms, String.format("android-%s", getVersion())); //$NON-NLS-1$
// TODO find similar existing platform in platforms folder // TODO find similar existing platform in platforms folder

View File

@@ -17,6 +17,7 @@
package com.android.sdklib.internal.repository; package com.android.sdklib.internal.repository;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.repository.Archive.Arch; import com.android.sdklib.internal.repository.Archive.Arch;
import com.android.sdklib.internal.repository.Archive.Os; import com.android.sdklib.internal.repository.Archive.Os;
@@ -82,10 +83,13 @@ public class ToolPackage extends Package {
* A "tool" package should always be located in SDK/tools. * A "tool" package should always be located in SDK/tools.
* *
* @param osSdkRoot The OS path of the SDK root folder. * @param osSdkRoot The OS path of the SDK root folder.
* @param suggestedDir A suggestion for the installation folder name, based on the root
* folder used in the zip archive.
* @param sdkManager An existing SDK manager to list current platforms and addons.
* @return A new {@link File} corresponding to the directory to use to install this package. * @return A new {@link File} corresponding to the directory to use to install this package.
*/ */
@Override @Override
public File getInstallFolder(String osSdkRoot) { public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
return new File(osSdkRoot, SdkConstants.FD_TOOLS); return new File(osSdkRoot, SdkConstants.FD_TOOLS);
} }

View File

@@ -101,7 +101,8 @@ class LocalSdkAdapter {
if (packages == null) { if (packages == null) {
// load on demand the first time // load on demand the first time
packages = parser.parseSdk(mUpdaterData.getOsSdkRoot()); packages = parser.parseSdk(mUpdaterData.getOsSdkRoot(),
mUpdaterData.getSdkManager());
} }
if (packages != null) { if (packages != null) {

View File

@@ -273,7 +273,7 @@ class UpdaterData {
break; break;
} }
if (archive.install(mOsSdkRoot, forceHttp, monitor)) { if (archive.install(mOsSdkRoot, forceHttp, mSdkManager, monitor)) {
numInstalled++; numInstalled++;
} }