Merge change 2384 into donut

* changes:
  SDK Updater: display properties of sources and packages.
This commit is contained in:
Android (Google) Code Review
2009-05-22 17:20:35 -07:00
9 changed files with 458 additions and 116 deletions

View File

@@ -20,35 +20,110 @@ import com.android.sdklib.repository.SdkRepository;
import org.w3c.dom.Node;
import java.util.ArrayList;
/**
*
* Represents an add-on XML node in an SDK repository.
*/
public class AddonPackage extends Package {
private final String mVendor;
private final String mName;
private final String mApiLevel;
private final int mApiLevel;
public AddonPackage(Node packageNode) {
/** An add-on library. */
public static class Lib {
private final String mName;
private final String mDescription;
public Lib(String name, String description) {
mName = name;
mDescription = description;
}
public String getName() {
return mName;
}
public String getDescription() {
return mDescription;
}
}
private final Lib[] mLibs;
/**
* Creates a new add-on package from the attributes and elements of the given XML node.
* <p/>
* This constructor should throw an exception if the package cannot be created.
*/
AddonPackage(Node packageNode) {
super(packageNode);
mVendor = getXmlString(packageNode, SdkRepository.NODE_VENDOR);
mName = getXmlString(packageNode, SdkRepository.NODE_NAME);
mApiLevel = getXmlString(packageNode, SdkRepository.NODE_API_LEVEL);
mApiLevel = getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
// TODO libs
mLibs = parseLibs(getFirstChild(packageNode, SdkRepository.NODE_LIBS));
}
private Lib[] parseLibs(Node libsNode) {
ArrayList<Lib> libs = new ArrayList<Lib>();
if (libsNode != null) {
for(Node child = libsNode.getFirstChild();
child != null;
child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&
SdkRepository.NODE_LIB.equals(child.getLocalName())) {
libs.add(parseLib(child));
}
}
}
return libs.toArray(new Lib[libs.size()]);
}
private Lib parseLib(Node libNode) {
return new Lib(getXmlString(libNode, SdkRepository.NODE_NAME),
getXmlString(libNode, SdkRepository.NODE_DESCRIPTION));
}
/** Returns the vendor, a string, for add-on packages. */
public String getVendor() {
return mVendor;
}
/** Returns the name, a string, for add-on packages or for libraries. */
public String getName() {
return mName;
}
public String getApiLevel() {
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
public int getApiLevel() {
return mApiLevel;
}
/** Returns the libs defined in this add-on. Can be an empty array but not null. */
public Lib[] getLibs() {
return mLibs;
}
/** Returns a short description for an {@link IDescription}. */
@Override
public String getShortDescription() {
return String.format("%1$s by %2$s for Android API %3$d",
getName(),
getVendor(),
getApiLevel());
}
/** Returns a long description for an {@link IDescription}. */
@Override
public String getLongDescription() {
return String.format("%1$s.\n%2$s",
getShortDescription(),
super.getLongDescription());
}
}

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdklib.internal.repository;
/**
* A {@link Archive} is the base class for "something" that can be downloaded from
* the SDK repository -- subclasses include {@link PlatformPackage}, {@link AddonPackage},
* {@link DocPackage} and {@link ToolPackage}.
* <p/>
* A package has some attributes (revision, description) and a list of archives
* which represent the downloadable bits.
* <p/>
* Packages are contained in offered by a {@link RepoSource} (a download site).
*/
public class Archive implements IDescription {
/** The checksum type. */
public enum ChecksumType {
/** A SHA1 checksum, represented as a 40-hex string. */
SHA1
}
/** The OS that this archive can be downloaded on. */
public enum Os {
ANY,
LINUX,
MACOSX,
WINDOWS
}
/** The Architecture that this archvie can be downloaded on. */
public enum Arch {
ANY,
PPC,
X86,
X86_64
}
private final Os mOs;
private final Arch mArch;
private final String mUrl;
private final long mSize;
private final String mChecksum;
private final ChecksumType mChecksumType = ChecksumType.SHA1;
/**
* Creates a new archive.
*/
Archive(Os os, Arch arch, String url, long size, String checksum) {
mOs = os;
mArch = arch;
mUrl = url;
mSize = size;
mChecksum = checksum;
}
/** Returns the archive size, an int > 0. */
public long getSize() {
return mSize;
}
/** Returns the SHA1 archive checksum, as a 40-char hex. */
public String getChecksum() {
return mChecksum;
}
/** Returns the checksum type, always {@link ChecksumType#SHA1} right now. */
public ChecksumType getChecksumType() {
return mChecksumType;
}
/** Returns the optional description URL for all packages (platform, add-on, tool, doc).
* Can be empty but not null. */
public String getDescUrl() {
return mUrl;
}
/** Returns the archive {@link Os} enum. */
public Os getOs() {
return mOs;
}
/** Returns the archive {@link Arch} enum. */
public Arch getArch() {
return mArch;
}
public String getShortDescription() {
String os = "any OS";
if (mOs != Os.ANY) {
os = capitalize(mOs.toString());
}
String arch = "";
if (mArch != Arch.ANY) {
arch = mArch.toString().toLowerCase();
}
return String.format("Archive for %1$s %2$s", os, arch);
}
private String capitalize(String string) {
if (string.length() > 1) {
return string.substring(0, 1).toUpperCase() + string.substring(1).toLowerCase();
} else {
return string.toUpperCase();
}
}
public String getLongDescription() {
return String.format("%1$s\nSize: %2$d MiB\nSHA1: %3$s",
getShortDescription(),
Math.round(getSize() / (1024*1024)),
getChecksum());
}
}

View File

@@ -16,14 +16,43 @@
package com.android.sdklib.internal.repository;
import com.android.sdklib.repository.SdkRepository;
import org.w3c.dom.Node;
/**
*
* Represents a doc XML node in an SDK repository.
*/
public class DocPackage extends Package {
public DocPackage(Node packageNode) {
private final int mApiLevel;
/**
* Creates a new doc package from the attributes and elements of the given XML node.
* <p/>
* This constructor should throw an exception if the package cannot be created.
*/
DocPackage(Node packageNode) {
super(packageNode);
mApiLevel = getXmlInt(packageNode, SdkRepository.NODE_API_LEVEL, 0);
}
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
public int getApiLevel() {
return mApiLevel;
}
/** Returns a short description for an {@link IDescription}. */
@Override
public String getShortDescription() {
return String.format("Documentation for SDK Android API %1$d", getApiLevel());
}
/** Returns a long description for an {@link IDescription}. */
@Override
public String getLongDescription() {
return String.format("%1$s.\n%2$s",
getShortDescription(),
super.getLongDescription());
}
}

View File

@@ -16,64 +16,133 @@
package com.android.sdklib.internal.repository;
import com.android.sdklib.internal.repository.Archive.Arch;
import com.android.sdklib.internal.repository.Archive.Os;
import com.android.sdklib.repository.SdkRepository;
import org.w3c.dom.Node;
import java.util.ArrayList;
/**
*
* A {@link Package} is the base class for "something" that can be downloaded from
* the SDK repository -- subclasses include {@link PlatformPackage}, {@link AddonPackage},
* {@link DocPackage} and {@link ToolPackage}.
* <p/>
* A package has some attributes (revision, description) and a list of archives
* which represent the downloadable bits.
* <p/>
* Packages are contained by a {@link RepoSource} (a download site).
* <p/>
* Derived classes must implement the {@link IDescription} methods.
*/
public class Package {
public abstract class Package implements IDescription {
private final int mRevision;
private final String mDescription;
private final String mDescUrl;
private final Archive[] mArchives;
private Package(int revision, String description, String descUrl) {
mRevision = revision;
mDescription = description;
mDescUrl = descUrl;
/**
* Creates a new package from the attributes and elements of the given XML node.
* <p/>
* This constructor should throw an exception if the package cannot be created.
*/
Package(Node packageNode) {
mRevision = getXmlInt (packageNode, SdkRepository.NODE_REVISION, 0);
mDescription = getXmlString(packageNode, SdkRepository.NODE_DESCRIPTION);
mDescUrl = getXmlString(packageNode, SdkRepository.NODE_DESC_URL);
mArchives = parseArchives(getFirstChild(packageNode, SdkRepository.NODE_ARCHIVES));
}
public Package(Node packageNode) {
this(getXmlInt (packageNode, SdkRepository.NODE_REVISION, 0),
getXmlString(packageNode, SdkRepository.NODE_DESCRIPTION),
getXmlString(packageNode, SdkRepository.NODE_DESC_URL));
private Archive[] parseArchives(Node archivesNode) {
ArrayList<Archive> archives = new ArrayList<Archive>();
// TODO archives
if (archivesNode != null) {
for(Node child = archivesNode.getFirstChild();
child != null;
child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&
SdkRepository.NODE_ARCHIVE.equals(child.getLocalName())) {
archives.add(parseArchive(child));
}
}
}
return archives.toArray(new Archive[archives.size()]);
}
/** The revision, an int > 0, for all packages (platform, add-on, tool, doc). */
private Archive parseArchive(Node archiveNode) {
Archive a = new Archive(
(Os) getEnumAttribute(archiveNode, SdkRepository.ATTR_OS,
Os.values(), null),
(Arch) getEnumAttribute(archiveNode, SdkRepository.ATTR_ARCH,
Arch.values(), Arch.ANY),
getXmlString(archiveNode, SdkRepository.NODE_URL),
getXmlInt(archiveNode, SdkRepository.NODE_SIZE, 0),
getXmlString(archiveNode, SdkRepository.NODE_CHECKSUM)
);
return a;
}
/** Returns the revision, an int > 0, for all packages (platform, add-on, tool, doc). */
public int getRevision() {
return mRevision;
}
/** The optional description for all packages (platform, add-on, tool, doc) or for a lib. */
/** Returns the optional description for all packages (platform, add-on, tool, doc) or
* for a lib. */
public String getDescription() {
return mDescription;
}
/** The optional description URL for all packages (platform, add-on, tool, doc).
/** Returns the optional description URL for all packages (platform, add-on, tool, doc).
* Can be empty but not null. */
public String getDescUrl() {
return mDescUrl;
}
/** Returns the archives defined in this package. Can be an empty array but not null. */
public Archive[] getArchives() {
return mArchives;
}
/** Returns a short description for an {@link IDescription}. */
public abstract String getShortDescription();
/** Returns a long description for an {@link IDescription}. */
public String getLongDescription() {
return String.format("%1$s\nRevision %2$d", getDescription(), getRevision());
}
//---
protected static Node getFirstChild(Node node, String xmlLocalName) {
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI())) {
if (xmlLocalName == null || xmlLocalName.equals(child.getLocalName())) {
return child;
}
}
}
return null;
}
/**
* Retrieves the value of that XML element as a string.
* Returns an empty string when the element is missing.
*/
protected static String getXmlString(Node node, String xmlLocalName) {
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
child.getNamespaceURI().equals(SdkRepository.NS_SDK_REPOSITORY)) {
if (xmlLocalName == null || child.getLocalName().equals(xmlLocalName)) {
return child.getTextContent();
}
}
}
Node child = getFirstChild(node, xmlLocalName);
return "";
return child == null ? "" : child.getTextContent(); //$NON-NLS-1$
}
/**
@@ -89,4 +158,29 @@ public class Package {
}
}
/**
* Retrieve an attribute which value must match one of the given enums using a
* case-insensitive name match.
*
* Returns defaultValue if the attribute does not exist or its value does not match
* the given enum values.
*/
private Object getEnumAttribute(
Node archiveNode,
String attrName,
Object[] values,
Object defaultValue) {
Node attr = archiveNode.getAttributes().getNamedItem(attrName);
if (attr != null) {
String found = attr.getNodeValue();
for (Object value : values) {
if (value.toString().equalsIgnoreCase(found)) {
return value;
}
}
}
return defaultValue;
}
}

View File

@@ -21,26 +21,47 @@ import com.android.sdklib.repository.SdkRepository;
import org.w3c.dom.Node;
/**
*
* Represents a platform XML node in an SDK repository.
*/
public class PlatformPackage extends Package {
private final String mVersion;
private final String mApiLevel;
private final int mApiLevel;
public PlatformPackage(Node packageNode) {
/**
* Creates a new platform package from the attributes and elements of the given XML node.
* <p/>
* This constructor should throw an exception if the package cannot be created.
*/
PlatformPackage(Node packageNode) {
super(packageNode);
mVersion = getXmlString(packageNode, SdkRepository.NODE_VERSION);
mApiLevel = getXmlString(packageNode, SdkRepository.NODE_API_LEVEL);
mApiLevel = getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
}
/** Returns the version, a string, for platform packages. */
public String getVersion() {
return mVersion;
}
public String getApiLevel() {
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
public int getApiLevel() {
return mApiLevel;
}
/** Returns a short description for an {@link IDescription}. */
@Override
public String getShortDescription() {
return String.format("SDK Platform Android %1$s, API %2$d",
getVersion(),
getApiLevel());
}
/** Returns a long description for an {@link IDescription}. */
@Override
public String getLongDescription() {
return String.format("%1$s.\n%2$s",
getShortDescription(),
super.getLongDescription());
}
}

View File

@@ -41,14 +41,16 @@ import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
/**
* An sdk-repository source. It may be a full repository or an add-on only repository.
* An sdk-repository source, i.e. a download site.
* It may be a full repository or an add-on only repository.
* A repository describes one or {@link Package}s available for download.
*/
public class RepoSource implements IDescription {
private final String mUrl;
private final boolean mAddonOnly;
private ArrayList<String> mPackages;
private Package[] mPackages;
private String mDescription;
/**
@@ -68,7 +70,7 @@ public class RepoSource implements IDescription {
/**
* Returns the list of known packages. This is null when the source hasn't been loaded yet.
*/
public ArrayList<String> getPackages() {
public Package[] getPackages() {
return mPackages;
}
@@ -112,12 +114,12 @@ public class RepoSource implements IDescription {
monitor.setDescription("Parse XML");
monitor.incProgress(1);
parsePackages(xml, monitor);
if (mPackages.size() == 0) {
if (mPackages.length == 0) {
mDescription += "\nNo packages found.";
} else if (mPackages.size() == 1) {
} else if (mPackages.length == 1) {
mDescription += "\nOne package found.";
} else {
mDescription += String.format("\n%1$d packages found.", mPackages.size());
mDescription += String.format("\n%1$d packages found.", mPackages.length);
}
// done
@@ -223,32 +225,43 @@ public class RepoSource implements IDescription {
Node root = getFirstChild(doc, SdkRepository.NODE_SDK_REPOSITORY);
if (root != null) {
mPackages = new ArrayList<String>();
ArrayList<Package> packages = new ArrayList<Package>();
for (Node child = root.getFirstChild();
child != null;
child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
child.getNamespaceURI().equals(SdkRepository.NS_SDK_REPOSITORY)) {
SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI())) {
String name = child.getLocalName();
if (SdkRepository.NODE_ADD_ON.equals(name)) {
parseAddon(child, mPackages, monitor);
Package p = null;
} else if (!mAddonOnly) {
if (SdkRepository.NODE_PLATFORM.equals(name)) {
parsePlatform(child, mPackages, monitor);
} else if (SdkRepository.NODE_DOC.equals(name)) {
parseDoc(child, mPackages, monitor);
} else if (SdkRepository.NODE_TOOL.equals(name)) {
parseTool(child, mPackages, monitor);
try {
if (SdkRepository.NODE_ADD_ON.equals(name)) {
p = new AddonPackage(child);
} else if (!mAddonOnly) {
if (SdkRepository.NODE_PLATFORM.equals(name)) {
p = new PlatformPackage(child);
} else if (SdkRepository.NODE_DOC.equals(name)) {
p = new DocPackage(child);
} else if (SdkRepository.NODE_TOOL.equals(name)) {
p = new ToolPackage(child);
}
}
if (p != null) {
packages.add(p);
monitor.setDescription(
String.format("Found %1$s", p.getShortDescription()));
}
} catch (Exception e) {
// Ignore invalid packages
}
}
}
mPackages = packages.toArray(new Package[packages.size()]);
return true;
}
@@ -269,7 +282,7 @@ public class RepoSource implements IDescription {
for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child.getNodeType() == Node.ELEMENT_NODE &&
child.getNamespaceURI().equals(SdkRepository.NS_SDK_REPOSITORY)) {
SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI())) {
if (xmlLocalName == null || child.getLocalName().equals(xmlLocalName)) {
return child;
}
@@ -290,42 +303,4 @@ public class RepoSource implements IDescription {
return doc;
}
private void parseAddon(Node addon, ArrayList<String> packages, ITaskMonitor monitor) {
// TODO Auto-generated method stub
String s = String.format("addon %1$s by %2$s, api %3$s, rev %4$s",
getFirstChild(addon, SdkRepository.NODE_NAME).getTextContent(),
getFirstChild(addon, SdkRepository.NODE_VENDOR).getTextContent(),
getFirstChild(addon, SdkRepository.NODE_API_LEVEL).getTextContent(),
getFirstChild(addon, SdkRepository.NODE_REVISION).getTextContent()
);
packages.add(s);
}
private void parsePlatform(Node platform, ArrayList<String> packages, ITaskMonitor monitor) {
// TODO Auto-generated method stub
String s = String.format("platform %1$s, api %2$s, rev %3$s",
getFirstChild(platform, SdkRepository.NODE_VERSION).getTextContent(),
getFirstChild(platform, SdkRepository.NODE_API_LEVEL).getTextContent(),
getFirstChild(platform, SdkRepository.NODE_REVISION).getTextContent()
);
packages.add(s);
}
private void parseDoc(Node doc, ArrayList<String> packages, ITaskMonitor monitor) {
// TODO Auto-generated method stub
String s = String.format("doc for api %1$s, rev %2$s",
getFirstChild(doc, SdkRepository.NODE_API_LEVEL).getTextContent(),
getFirstChild(doc, SdkRepository.NODE_REVISION).getTextContent()
);
packages.add(s);
}
private void parseTool(Node tool, ArrayList<String> packages, ITaskMonitor monitor) {
// TODO Auto-generated method stub
String s = String.format("tool, rev %1$s",
getFirstChild(tool, SdkRepository.NODE_REVISION).getTextContent()
);
packages.add(s);
}
}

View File

@@ -16,25 +16,33 @@
package com.android.sdklib.internal.repository;
import com.android.sdklib.repository.SdkRepository;
import org.w3c.dom.Node;
/**
*
* Represents a tool XML node in an SDK repository.
*/
public class ToolPackage extends Package {
private final String mApiLevel;
public ToolPackage(Node packageNode) {
/**
* Creates a new tool package from the attributes and elements of the given XML node.
* <p/>
* This constructor should throw an exception if the package cannot be created.
*/
ToolPackage(Node packageNode) {
super(packageNode);
mApiLevel = getXmlString(packageNode, SdkRepository.NODE_API_LEVEL);
}
public String getApiLevel() {
return mApiLevel;
/** Returns a short description for an {@link IDescription}. */
@Override
public String getShortDescription() {
return String.format("Android SDK Tools, revision %1$d", getRevision());
}
/** Returns a long description for an {@link IDescription}. */
@Override
public String getLongDescription() {
return String.format("Android SDK Tools, revision %1$d.\n%2$s",
getRevision(),
super.getLongDescription());
}
}

View File

@@ -61,9 +61,9 @@ public class SdkRepository {
public static final String NODE_LIB = "lib"; //$NON-NLS-1$
/** The archives container, for all packages. */
public static final String NODE_ARCHVIES = "archives"; //$NON-NLS-1$
public static final String NODE_ARCHIVES = "archives"; //$NON-NLS-1$
/** An archive element, for the archives container. */
public static final String NODE_ARCHVIE = "archive"; //$NON-NLS-1$
public static final String NODE_ARCHIVE = "archive"; //$NON-NLS-1$
/** An archive size, an int > 0. */
public static final String NODE_SIZE = "size"; //$NON-NLS-1$
@@ -72,10 +72,12 @@ public class SdkRepository {
/** A download archive URL, either absolute or relative to the repository xml. */
public static final String NODE_URL = "url"; //$NON-NLS-1$
/** An archive checksum type, mandatory. */
public static final String ATTR_TYPE = "type"; //$NON-NLS-1$
/** An archive OS attribute, mandatory. */
public static final String NODE_OS = "os"; //$NON-NLS-1$
public static final String ATTR_OS = "os"; //$NON-NLS-1$
/** An optional archive Architecture attribute. */
public static final String NODE_ARCH = "arch"; //$NON-NLS-1$
public static final String ATTR_ARCH = "arch"; //$NON-NLS-1$
public static InputStream getXsdStream() {
return SdkRepository.class.getResourceAsStream("sdk-repository.xsd"); //$NON-NLS-1$