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.
*
* @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.
*/
@Override
public File getInstallFolder(String osSdkRoot) {
public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
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
// happen: a Chinese or Japanese name etc for example,
// to name a few.
name = name.toLowerCase();
name = name.replaceAll("[^a-zA-Z0-9_-]+", "_"); // $NON-NLS-1$
name = name.replaceAll("_+", "_"); // $NON-NLS-1$
// Otherwise, see about reusing the suggestedDir. It must not be already used or
// add some index to it, or we try to make up one.
String name = suggestedDir;
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
return folder;
for (int i = 0; i < 100; i++) {
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;
import com.android.sdklib.SdkManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -341,7 +343,10 @@ public class Archive implements IDescription {
*
* @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;
try {
@@ -364,7 +369,7 @@ public class Archive implements IDescription {
archiveFile = downloadFile(monitor, forceHttp);
if (archiveFile != null) {
if (unarchive(osSdkRoot, archiveFile, monitor)) {
if (unarchive(osSdkRoot, archiveFile, sdkManager, monitor)) {
monitor.setResult("Installed: %1$s", name);
return true;
}
@@ -568,48 +573,63 @@ public class Archive implements IDescription {
/**
* Install the given archive in the given folder.
*/
private boolean unarchive(String osSdkRoot, File archiveFile, ITaskMonitor monitor) {
String name = getParentPackage().getShortDescription();
String desc = String.format("Installing %1$s", name);
monitor.setDescription(desc);
private boolean unarchive(String osSdkRoot,
File archiveFile,
SdkManager sdkManager,
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;
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$
// Find a new temp folder that doesn't exist yet
unzipDestFolder = findTempFolder(osSdkRoot, pkgKind, "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 == null) {
// this should not seriously happen.
monitor.setResult("Failed to find a temp directory in %1$s.", osSdkRoot);
return false;
}
if (!unzipDestFolder.mkdirs()) {
monitor.setResult("Failed to create directory %1$s",
unzipDestFolder.getPath());
monitor.setResult("Failed to create directory %1$s", unzipDestFolder.getPath());
return false;
}
if (!unzipFolder(archiveFile, getSize(), unzipDestFolder, desc, monitor)) {
String[] zipRootFolder = new String[] { null };
if (!unzipFolder(archiveFile, getSize(),
unzipDestFolder, pkgDesc,
zipRootFolder, 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$
// Compute destination directory
destFolder = getParentPackage().getInstallFolder(
osSdkRoot, zipRootFolder[0], sdkManager);
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) {
// this should not seriously happen.
monitor.setResult("Failed to find a suitable temp directory similar to %1$s.",
destFolder.getPath());
monitor.setResult("Failed to find a temp directory in %1$s.", osSdkRoot);
return false;
}
@@ -619,28 +639,36 @@ public class Archive implements IDescription {
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;
} finally {
// Cleanup if the unzip folder is still set.
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,
long compressedSize,
File unzipDestFolder,
String description,
String[] outZipRootFolder,
ITaskMonitor monitor) {
description += " (%1$d%%)";
@@ -678,6 +706,9 @@ public class Archive implements IDescription {
if (pos < 0 || pos == name.length() - 1) {
continue;
} else {
if (outZipRootFolder[0] == null && pos > 0) {
outZipRootFolder[0] = name.substring(0, pos);
}
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
* and with a ".tmpN" appended.
* Finds a temp folder in the form of osBasePath/temp/prefix.suffixNNN.
* <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.
* Returns null if no such folder can be found (e.g. if all candidates exist,
* which is rather unlikely) or if the base temp folder cannot be created.
*/
private File findTempFolder(File idealFolder, String suffix) {
String basePath = idealFolder.getPath();
private File findTempFolder(String osBasePath, String prefix, String suffix) {
File baseTempFolder = new File(osBasePath, "temp");
if (!baseTempFolder.isDirectory()) {
if (!baseTempFolder.mkdirs()) {
return null;
}
}
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()) {
return folder;
}

View File

@@ -17,6 +17,7 @@
package com.android.sdklib.internal.repository;
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.Os;
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.
*
* @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.
*/
@Override
public File getInstallFolder(String osSdkRoot) {
public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
return new File(osSdkRoot, SdkConstants.FD_DOCS);
}

View File

@@ -17,7 +17,6 @@
package com.android.sdklib.internal.repository;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
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() {
return mPackages;
@@ -71,7 +70,7 @@ public class LocalSdkParser {
/**
* 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() {
mPackages = null;
@@ -84,9 +83,10 @@ public class LocalSdkParser {
* at any time later.
*
* @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()}.
*/
public Package[] parseSdk(String osSdkRoot) {
public Package[] parseSdk(String osSdkRoot, SdkManager sdkManager) {
ArrayList<Package> packages = new ArrayList<Package>();
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
SdkManager sdkman = SdkManager.createManager(osSdkRoot, new ISdkLog() {
// 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()) {
for(IAndroidTarget target : sdkManager.getTargets()) {
pkg = null;
if (target.isPlatform()) {

View File

@@ -16,6 +16,7 @@
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.Os;
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.
*
* @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.
*/
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.

View File

@@ -102,10 +102,23 @@ public class PlatformPackage extends Package {
* has this platform version installed, we'll use that one.
*
* @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.
*/
@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 folder = new File(platforms, String.format("android-%s", getVersion())); //$NON-NLS-1$
// TODO find similar existing platform in platforms folder

View File

@@ -17,6 +17,7 @@
package com.android.sdklib.internal.repository;
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.Os;
@@ -82,10 +83,13 @@ public class ToolPackage extends Package {
* A "tool" package should always be located in SDK/tools.
*
* @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.
*/
@Override
public File getInstallFolder(String osSdkRoot) {
public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
return new File(osSdkRoot, SdkConstants.FD_TOOLS);
}

View File

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

View File

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