OSDN Git Service

SDK Updater: Store local source properties when installing.
authorRaphael <raphael@google.com>
Fri, 26 Jun 2009 21:33:40 +0000 (14:33 -0700)
committerRaphael <raphael@google.com>
Fri, 26 Jun 2009 21:37:01 +0000 (14:37 -0700)
When installing an archive, a "source.properties" file is saved
in the directory that contains all the information from the
source (Source URL, package attributes, archive attributes.)

When loading local packages, these properties are used to
recreate the local package attributes if present. This is
also used to indentify local extra packages.

tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DocPackage.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ExtraPackage.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/LocalSdkParser.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Package.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ToolPackage.java
tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/LocalSdkAdapter.java

index e273a54..7908322 100755 (executable)
@@ -29,12 +29,17 @@ import org.w3c.dom.Node;
 import java.io.File;\r
 import java.util.ArrayList;\r
 import java.util.Map;\r
+import java.util.Properties;\r
 \r
 /**\r
  * Represents an add-on XML node in an SDK repository.\r
  */\r
 public class AddonPackage extends Package {\r
 \r
+    private static final String PROP_API_LEVEL = "Addon.ApiLevel";  //$NON-NLS-1$\r
+    private static final String PROP_NAME      = "Addon.Name";      //$NON-NLS-1$\r
+    private static final String PROP_VENDOR    = "Addon.Vendor";    //$NON-NLS-1$\r
+\r
     private final String mVendor;\r
     private final String mName;\r
     private final int    mApiLevel;\r
@@ -80,8 +85,9 @@ public class AddonPackage extends Package {
      * This is used to list local SDK folders in which case there is one archive which\r
      * URL is the actual target location.\r
      */\r
-    AddonPackage(IAndroidTarget target) {\r
+    AddonPackage(IAndroidTarget target, Properties props) {\r
         super(  null,                       //source\r
+                props,                      //properties\r
                 0,                          //revision\r
                 null,                       //license\r
                 target.getDescription(),    //description\r
@@ -107,6 +113,19 @@ public class AddonPackage extends Package {
     }\r
 \r
     /**\r
+     * Save the properties of the current packages in the given {@link Properties} object.\r
+     * These properties will later be give the constructor that takes a {@link Properties} object.\r
+     */\r
+    @Override\r
+    void saveProperties(Properties props) {\r
+        super.saveProperties(props);\r
+\r
+        props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));\r
+        props.setProperty(PROP_NAME, mName);\r
+        props.setProperty(PROP_VENDOR, mVendor);\r
+    }\r
+\r
+    /**\r
      * Parses a <libs> element.\r
      */\r
     private Lib[] parseLibs(Node libsNode) {\r
index 191ef19..c34e859 100755 (executable)
@@ -26,6 +26,7 @@ import java.io.InputStream;
 import java.net.URL;\r
 import java.security.MessageDigest;\r
 import java.security.NoSuchAlgorithmException;\r
+import java.util.Properties;\r
 import java.util.zip.ZipEntry;\r
 import java.util.zip.ZipInputStream;\r
 \r
@@ -43,6 +44,8 @@ import java.util.zip.ZipInputStream;
 public class Archive implements IDescription {\r
 \r
     public static final int NUM_MONITOR_INC = 100;\r
+    private static final String PROP_OS   = "Archive.Os";       //$NON-NLS-1$\r
+    private static final String PROP_ARCH = "Archive.Arch";     //$NON-NLS-1$\r
 \r
     /** The checksum type. */\r
     public enum ChecksumType {\r
@@ -175,11 +178,14 @@ public class Archive implements IDescription {
 \r
     /**\r
      * Creates a new local archive.\r
+     * Uses the properties from props first, if possible. Props can be null.\r
      */\r
-    Archive(Package pkg, Os os, Arch arch, String localOsPath) {\r
+    Archive(Package pkg, Properties props, Os os, Arch arch, String localOsPath) {\r
         mPackage = pkg;\r
-        mOs = os;\r
-        mArch = arch;\r
+\r
+        mOs   = props == null ? os   : Os.valueOf(  props.getProperty(PROP_OS,   os.toString()));\r
+        mArch = props == null ? arch : Arch.valueOf(props.getProperty(PROP_ARCH, arch.toString()));\r
+\r
         mUrl = null;\r
         mLocalOsPath = localOsPath;\r
         mSize = 0;\r
@@ -188,6 +194,15 @@ public class Archive implements IDescription {
     }\r
 \r
     /**\r
+     * Save the properties of the current archive in the give {@link Properties} object.\r
+     * These properties will later be give the constructor that takes a {@link Properties} object.\r
+     */\r
+    void saveProperties(Properties props) {\r
+        props.setProperty(PROP_OS,   mOs.toString());\r
+        props.setProperty(PROP_ARCH, mArch.toString());\r
+    }\r
+\r
+    /**\r
      * Returns true if this is a locally installed archive.\r
      * Returns false if this is a remote archive that needs to be downloaded.\r
      */\r
@@ -623,6 +638,10 @@ public class Archive implements IDescription {
                 return false;\r
             }\r
 \r
+            if (!generateSourceProperties(unzipDestFolder)) {\r
+                return false;\r
+            }\r
+\r
             // Compute destination directory\r
             destFolder = getParentPackage().getInstallFolder(\r
                     osSdkRoot, zipRootFolder[0], sdkManager);\r
@@ -848,5 +867,40 @@ public class Archive implements IDescription {
             }\r
         }\r
     }\r
-}\r
 \r
+    /**\r
+     * Generates a source.properties in the destination folder that contains all the infos\r
+     * relevant to this archive, this package and the source so that we can reload them\r
+     * locally later.\r
+     */\r
+    private boolean generateSourceProperties(File unzipDestFolder) {\r
+        Properties props = new Properties();\r
+\r
+        saveProperties(props);\r
+        mPackage.saveProperties(props);\r
+\r
+        FileOutputStream fos = null;\r
+        try {\r
+            File f = new File(unzipDestFolder, LocalSdkParser.SOURCE_PROPERTIES);\r
+\r
+            fos = new FileOutputStream(f);\r
+\r
+            props.store( fos, "## Android Tool: Source of this archive.");  //$NON-NLS-1$\r
+\r
+            return true;\r
+        } catch (IOException e) {\r
+            e.printStackTrace();\r
+        } finally {\r
+            if (fos != null) {\r
+                try {\r
+                    fos.close();\r
+                } catch (IOException e) {\r
+                }\r
+            }\r
+        }\r
+\r
+        return false;\r
+    }\r
+\r
+\r
+}\r
index e7fa893..c1b8d1d 100755 (executable)
@@ -26,12 +26,15 @@ import org.w3c.dom.Node;
 \r
 import java.io.File;\r
 import java.util.Map;\r
+import java.util.Properties;\r
 \r
 /**\r
  * Represents a doc XML node in an SDK repository.\r
  */\r
 public class DocPackage extends Package {\r
 \r
+    private static final String PROP_API_LEVEL = "Doc.ApiLevel";  //$NON-NLS-1$\r
+\r
     private final int mApiLevel;\r
 \r
     /**\r
@@ -50,6 +53,7 @@ public class DocPackage extends Package {
      * one archive which URL is the actual target location.\r
      */\r
     DocPackage(RepoSource source,\r
+            Properties props,\r
             int apiLevel,\r
             int revision,\r
             String license,\r
@@ -59,6 +63,7 @@ public class DocPackage extends Package {
             Arch archiveArch,\r
             String archiveOsPath) {\r
         super(source,\r
+                props,\r
                 revision,\r
                 license,\r
                 description,\r
@@ -66,7 +71,19 @@ public class DocPackage extends Package {
                 archiveOs,\r
                 archiveArch,\r
                 archiveOsPath);\r
-        mApiLevel = apiLevel;\r
+        mApiLevel = Integer.parseInt(\r
+                        getProperty(props, PROP_API_LEVEL, Integer.toString(apiLevel)));\r
+    }\r
+\r
+    /**\r
+     * Save the properties of the current packages in the given {@link Properties} object.\r
+     * These properties will later be give the constructor that takes a {@link Properties} object.\r
+     */\r
+    @Override\r
+    void saveProperties(Properties props) {\r
+        super.saveProperties(props);\r
+\r
+        props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));\r
     }\r
 \r
     /** Returns the api-level, an int > 0, for platform, add-on and doc packages.\r
index 9cd602c..f9d3752 100755 (executable)
@@ -26,12 +26,15 @@ import org.w3c.dom.Node;
 \r
 import java.io.File;\r
 import java.util.Map;\r
+import java.util.Properties;\r
 \r
 /**\r
  * Represents a extra XML node in an SDK repository.\r
  */\r
 public class ExtraPackage extends Package {\r
 \r
+    private static final String PROP_PATH = "Extra.Path";  //$NON-NLS-1$\r
+\r
     private final String mPath;\r
 \r
     /**\r
@@ -45,11 +48,12 @@ public class ExtraPackage extends Package {
     }\r
 \r
     /**\r
-     * Manually create a new package with one archive and the given attributes.\r
+     * Manually create a new package with one archive and the given attributes or properties.\r
      * This is used to create packages from local directories in which case there must be\r
      * one archive which URL is the actual target location.\r
      */\r
     ExtraPackage(RepoSource source,\r
+            Properties props,\r
             String path,\r
             int revision,\r
             String license,\r
@@ -59,6 +63,7 @@ public class ExtraPackage extends Package {
             Arch archiveArch,\r
             String archiveOsPath) {\r
         super(source,\r
+                props,\r
                 revision,\r
                 license,\r
                 description,\r
@@ -66,7 +71,19 @@ public class ExtraPackage extends Package {
                 archiveOs,\r
                 archiveArch,\r
                 archiveOsPath);\r
-        mPath = path;\r
+        // The path argument comes before whatever could be in the properties\r
+        mPath = path != null ? path : getProperty(props, PROP_PATH, path);\r
+    }\r
+\r
+    /**\r
+     * Save the properties of the current packages in the given {@link Properties} object.\r
+     * These properties will later be give the constructor that takes a {@link Properties} object.\r
+     */\r
+    @Override\r
+    void saveProperties(Properties props) {\r
+        super.saveProperties(props);\r
+\r
+        props.setProperty(PROP_PATH, mPath);\r
     }\r
 \r
     /**\r
index 91e264c..0e3b204 100755 (executable)
 package com.android.sdklib.internal.repository;\r
 \r
 import com.android.sdklib.IAndroidTarget;\r
+import com.android.sdklib.ISdkLog;\r
 import com.android.sdklib.SdkConstants;\r
 import com.android.sdklib.SdkManager;\r
 import com.android.sdklib.internal.repository.Archive.Arch;\r
 import com.android.sdklib.internal.repository.Archive.Os;\r
-import com.android.sdklib.repository.SdkRepository;\r
 \r
-import org.w3c.dom.Document;\r
-import org.w3c.dom.Node;\r
-import org.xml.sax.InputSource;\r
-import org.xml.sax.SAXException;\r
-\r
-import java.io.BufferedReader;\r
 import java.io.File;\r
-import java.io.FileReader;\r
+import java.io.FileInputStream;\r
 import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.StringReader;\r
 import java.util.ArrayList;\r
-import java.util.HashMap;\r
 import java.util.HashSet;\r
+import java.util.Properties;\r
 import java.util.Set;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-import javax.xml.XMLConstants;\r
-import javax.xml.parsers.DocumentBuilder;\r
-import javax.xml.parsers.DocumentBuilderFactory;\r
-import javax.xml.parsers.ParserConfigurationException;\r
-import javax.xml.transform.stream.StreamSource;\r
-import javax.xml.validation.Schema;\r
-import javax.xml.validation.SchemaFactory;\r
-import javax.xml.validation.Validator;\r
 \r
 /**\r
  * Scans a local SDK to find which packages are currently installed.\r
  */\r
 public class LocalSdkParser {\r
 \r
-    private static final String SOURCE_XML = "source.xml";  //$NON-NLS-1$ // TODO move to global constants\r
+    static final String SOURCE_PROPERTIES = "source.properties";  //$NON-NLS-1$\r
     private Package[] mPackages;\r
 \r
     public LocalSdkParser() {\r
@@ -63,7 +44,7 @@ public class LocalSdkParser {
     }\r
 \r
     /**\r
-     * Returns the packages found by the last call to {@link #parseSdk(String, SdkManager)}.\r
+     * Returns the packages found by the last call to {@link #parseSdk(String, SdkManager, ISdkLog)}.\r
      */\r
     public Package[] getPackages() {\r
         return mPackages;\r
@@ -71,7 +52,7 @@ public class LocalSdkParser {
 \r
     /**\r
      * Clear the internal packages list. After this call, {@link #getPackages()} will return\r
-     * null till {@link #parseSdk(String, SdkManager)} is called.\r
+     * null till {@link #parseSdk(String, SdkManager, ISdkLog)} is called.\r
      */\r
     public void clearPackages() {\r
         mPackages = null;\r
@@ -85,57 +66,102 @@ public class LocalSdkParser {
      *\r
      * @param osSdkRoot The path to the SDK folder.\r
      * @param sdkManager An existing SDK manager to list current platforms and addons.\r
+     * @param log An SDK logger object.\r
      * @return The packages found. Can be retrieved later using {@link #getPackages()}.\r
      */\r
-    public Package[] parseSdk(String osSdkRoot, SdkManager sdkManager) {\r
+    public Package[] parseSdk(String osSdkRoot, SdkManager sdkManager, ISdkLog log) {\r
         ArrayList<Package> packages = new ArrayList<Package>();\r
+        HashSet<File> visited = new HashSet<File>();\r
 \r
-        Package pkg = scanDoc(new File(osSdkRoot, SdkConstants.FD_DOCS));\r
+        File dir = new File(osSdkRoot, SdkConstants.FD_DOCS);\r
+        Package pkg = scanDoc(dir, log);\r
         if (pkg != null) {\r
             packages.add(pkg);\r
+            visited.add(dir);\r
         }\r
 \r
-        pkg = scanTools(new File(osSdkRoot, SdkConstants.FD_TOOLS));\r
+        dir = new File(osSdkRoot, SdkConstants.FD_TOOLS);\r
+        pkg = scanTools(dir, log);\r
         if (pkg != null) {\r
             packages.add(pkg);\r
+            visited.add(dir);\r
         }\r
 \r
         // for platforms and add-ons, rely on the SdkManager parser\r
         for(IAndroidTarget target : sdkManager.getTargets()) {\r
-            pkg = null;\r
-\r
-            if (target.isPlatform()) {\r
-                pkg = parseXml(new File(target.getLocation(), SOURCE_XML),\r
-                               SdkRepository.NODE_PLATFORM);\r
-                if (pkg == null) {\r
-                    pkg = new PlatformPackage(target);\r
-                }\r
 \r
-            } else {\r
-                pkg = parseXml(new File(target.getLocation(), SOURCE_XML),\r
-                                        SdkRepository.NODE_ADD_ON);\r
+            Properties props = parseProperties(new File(target.getLocation(), SOURCE_PROPERTIES));\r
 \r
-                if (pkg == null) {\r
-                    pkg = new AddonPackage(target);\r
+            try {\r
+                if (target.isPlatform()) {\r
+                    pkg = new PlatformPackage(target, props);\r
+                } else {\r
+                    pkg = new AddonPackage(target, props);\r
                 }\r
+            } catch (Exception e) {\r
+                log.error(e, null);\r
             }\r
 \r
             if (pkg != null) {\r
                 packages.add(pkg);\r
+                visited.add(new File(target.getLocation()));\r
             }\r
         }\r
 \r
+        scanExtra(osSdkRoot, visited, packages, log);\r
+\r
         mPackages = packages.toArray(new Package[packages.size()]);\r
         return mPackages;\r
     }\r
 \r
     /**\r
+     * Find any other directory what we haven't successfully visited and\r
+     * assume they contain extra packages.\r
+     * @param log\r
+     */\r
+    private void scanExtra(String osSdkRoot,\r
+            HashSet<File> visited,\r
+            ArrayList<Package> packages,\r
+            ISdkLog log) {\r
+        File root = new File(osSdkRoot);\r
+        for (File dir : root.listFiles()) {\r
+            if (dir.isDirectory() && !visited.contains(dir)) {\r
+\r
+                Properties props = parseProperties(new File(dir, SOURCE_PROPERTIES));\r
+                if (props != null) {\r
+                    try {\r
+                        ExtraPackage pkg = new ExtraPackage(\r
+                                null,                       //source\r
+                                props,                      //properties\r
+                                dir.getName(),              //path\r
+                                0,                          //revision\r
+                                null,                       //license\r
+                                "Tools",                    //description\r
+                                null,                       //descUrl\r
+                                Os.getCurrentOs(),          //archiveOs\r
+                                Arch.getCurrentArch(),      //archiveArch\r
+                                dir.getPath()               //archiveOsPath\r
+                                );\r
+\r
+                        // We only accept this as an extra package if it has a valid local path.\r
+                        if (pkg.isPathValid()) {\r
+                            packages.add(pkg);\r
+                        }\r
+                    } catch (Exception e) {\r
+                        log.error(e, null);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
      * Try to find a tools package at the given location.\r
      * Returns null if not found.\r
      */\r
-    private Package scanTools(File toolFolder) {\r
-        // Can we find a source.xml?\r
-        Package pkg = parseXml(new File(toolFolder, SOURCE_XML), SdkRepository.NODE_TOOL);\r
+    private Package scanTools(File toolFolder, ISdkLog log) {\r
+        // Can we find some properties?\r
+        Properties props = parseProperties(new File(toolFolder, SOURCE_PROPERTIES));\r
 \r
         // We're not going to check that all tools are present. At the very least\r
         // we should expect to find adb, android and an emulator adapted to the current OS.\r
@@ -149,10 +175,11 @@ public class LocalSdkParser {
             return null;\r
         }\r
 \r
-        // if we don't have the package info, make one up\r
-        if (pkg == null) {\r
-            pkg = new ToolPackage(\r
+        // Create are package. use the properties if we found any.\r
+        try {\r
+            ToolPackage pkg = new ToolPackage(\r
                     null,                       //source\r
+                    props,                      //properties\r
                     0,                          //revision\r
                     null,                       //license\r
                     "Tools",                    //description\r
@@ -161,77 +188,42 @@ public class LocalSdkParser {
                     Arch.getCurrentArch(),      //archiveArch\r
                     toolFolder.getPath()        //archiveOsPath\r
                     );\r
-        }\r
 \r
-        return pkg;\r
+            return pkg;\r
+        } catch (Exception e) {\r
+            log.error(e, null);\r
+        }\r
+        return null;\r
     }\r
 \r
     /**\r
      * Try to find a docs package at the given location.\r
      * Returns null if not found.\r
      */\r
-    private Package scanDoc(File docFolder) {\r
-        // Can we find a source.xml?\r
-        Package pkg = parseXml(new File(docFolder, SOURCE_XML), SdkRepository.NODE_DOC);\r
+    private Package scanDoc(File docFolder, ISdkLog log) {\r
+        // Can we find some properties?\r
+        Properties props = parseProperties(new File(docFolder, SOURCE_PROPERTIES));\r
 \r
         // To start with, a doc folder should have an "index.html" to be acceptable.\r
-        String html = readFile(new File(docFolder, "index.html"));\r
-        if (html != null) {\r
-            // Try to find something that looks like this line:\r
-            //   <a href="./sdk/1.5_r1/index.html">\r
-            // We should find one or more of these and we want the highest version\r
-            // and release numbers. Note that unfortunately that doesn't give us\r
-            // the api-level we care about for the doc package.\r
-\r
-            String found = null;\r
-            Pattern re = Pattern.compile(\r
-                    "<a\\s+href=\"./sdk/(\\d\\.\\d_r\\d)/index.html\">",\r
-                    Pattern.DOTALL);\r
-            Matcher m = re.matcher(html);\r
-            while(m.find()) {\r
-                String v = m.group(1);\r
-                if (found == null || v.compareTo(found) == 1) {\r
-                    found = v;\r
-                }\r
-            }\r
-\r
-            if (found == null) {\r
-                // That doesn't look like a doc folder.\r
-                return null;\r
-            }\r
-\r
-            // We found the line, so it seems like an SDK doc.\r
-            // Create a pkg if we don't have one yet.\r
-\r
-            if (pkg == null) {\r
-                pkg = new DocPackage(\r
+        // We don't actually check the content of the file.\r
+        if (new File(docFolder, "index.html").isFile()) {\r
+            try {\r
+                DocPackage pkg = new DocPackage(\r
                         null,                       //source\r
+                        props,                      //properties\r
                         0,                          //apiLevel\r
                         0,                          //revision\r
                         null,                       //license\r
-                        String.format("Documentation for %1$s", found),     //description\r
+                        null,                       //description\r
                         null,                       //descUrl\r
                         Os.getCurrentOs(),          //archiveOs\r
                         Arch.getCurrentArch(),      //archiveArch\r
                         docFolder.getPath()         //archiveOsPath\r
                         );\r
-            }\r
-        }\r
 \r
-        return pkg;\r
-    }\r
-\r
-    /**\r
-     * Parses the given XML file for the specific element filter.\r
-     * The element must one of the package type local names: doc, tool, platform or addon.\r
-     * Returns null if no such package was found.\r
-     */\r
-    private Package parseXml(File sourceXmlFile, String elementFilter) {\r
-\r
-        String xml = readFile(sourceXmlFile);\r
-        if (xml != null) {\r
-            if (validateXml(xml)) {\r
-                return parsePackages(xml, elementFilter);\r
+                return pkg;\r
+            } catch (Exception e) {\r
+                log.error(e, null);\r
             }\r
         }\r
 \r
@@ -239,170 +231,34 @@ public class LocalSdkParser {
     }\r
 \r
     /**\r
-     * Parses the given XML to find the specific element filter.\r
-     * The element must one of the package type local names: doc, tool, platform or addon.\r
-     * Returns null if no such package was found.\r
+     * Parses the given file as properties file if it exists.\r
+     * Returns null if the file does not exist, cannot be parsed or has no properties.\r
      */\r
-    private Package parsePackages(String xml, String elementFilter) {\r
-\r
+    private Properties parseProperties(File propsFile) {\r
+        FileInputStream fis = null;\r
         try {\r
-            Document doc = getDocument(xml);\r
-\r
-            Node root = getFirstChild(doc, SdkRepository.NODE_SDK_REPOSITORY);\r
-            if (root != null) {\r
-\r
-                // Parse license definitions\r
-                HashMap<String, String> licenses = new HashMap<String, String>();\r
-                for (Node child = root.getFirstChild();\r
-                     child != null;\r
-                     child = child.getNextSibling()) {\r
-                    if (child.getNodeType() == Node.ELEMENT_NODE &&\r
-                            SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&\r
-                            child.getLocalName().equals(SdkRepository.NODE_LICENSE)) {\r
-                        Node id = child.getAttributes().getNamedItem(SdkRepository.ATTR_ID);\r
-                        if (id != null) {\r
-                            licenses.put(id.getNodeValue(), child.getTextContent());\r
-                        }\r
-                    }\r
-                }\r
-\r
-                // Parse packages\r
-                for (Node child = root.getFirstChild();\r
-                     child != null;\r
-                     child = child.getNextSibling()) {\r
-                    if (child.getNodeType() == Node.ELEMENT_NODE &&\r
-                            SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&\r
-                            elementFilter.equals(child.getLocalName())) {\r
-                        String name = child.getLocalName();\r
-\r
-                        try {\r
-                            if (SdkRepository.NODE_ADD_ON.equals(name)) {\r
-                                return new AddonPackage(null /*source*/, child, licenses);\r
-\r
-                            } else if (SdkRepository.NODE_PLATFORM.equals(name)) {\r
-                                return new PlatformPackage(null /*source*/, child, licenses);\r
-\r
-                            } else if (SdkRepository.NODE_DOC.equals(name)) {\r
-                                return new DocPackage(null /*source*/, child, licenses);\r
-\r
-                            } else if (SdkRepository.NODE_TOOL.equals(name)) {\r
-                                return new ToolPackage(null /*source*/, child, licenses);\r
-                            }\r
-                        } catch (Exception e) {\r
-                            // Ignore invalid packages\r
-                        }\r
-                    }\r
-                }\r
-            }\r
-\r
-        } catch (Exception e) {\r
-            // ignore\r
-        }\r
+            if (propsFile.exists()) {\r
+                fis = new FileInputStream(propsFile);\r
 \r
-        return null;\r
-    }\r
+                Properties props = new Properties();\r
+                props.load(fis);\r
 \r
-    /**\r
-     * Reads a file as a string.\r
-     * Returns null if the file could not be read.\r
-     */\r
-    private String readFile(File sourceXmlFile) {\r
-        FileReader fr = null;\r
-        try {\r
-            fr = new FileReader(sourceXmlFile);\r
-            BufferedReader br = new BufferedReader(fr);\r
-            StringBuilder dest = new StringBuilder();\r
-            char[] buf = new char[65536];\r
-            int n;\r
-            while ((n = br.read(buf)) > 0) {\r
-                if (n > 0) {\r
-                    dest.append(buf, 0, n);\r
+                // To be valid, there must be at least one property in it.\r
+                if (props.size() > 0) {\r
+                    return props;\r
                 }\r
             }\r
-            return dest.toString();\r
 \r
         } catch (IOException e) {\r
-            // ignore\r
-\r
+            e.printStackTrace();\r
         } finally {\r
-            if (fr != null) {\r
+            if (fis != null) {\r
                 try {\r
-                    fr.close();\r
+                    fis.close();\r
                 } catch (IOException e) {\r
-                    // ignore\r
-                }\r
-            }\r
-        }\r
-\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * Validates this XML against the SDK Repository schema.\r
-     * Returns true if the XML was correctly validated.\r
-     */\r
-    private boolean validateXml(String xml) {\r
-\r
-        try {\r
-            Validator validator = getValidator();\r
-            validator.validate(new StreamSource(new StringReader(xml)));\r
-            return true;\r
-\r
-        } catch (SAXException e) {\r
-            // ignore\r
-\r
-        } catch (IOException e) {\r
-            // ignore\r
-        }\r
-\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * Helper method that returns a validator for our XSD\r
-     */\r
-    private Validator getValidator() throws SAXException {\r
-        InputStream xsdStream = SdkRepository.getXsdStream();\r
-        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);\r
-\r
-        // This may throw a SAX Exception if the schema itself is not a valid XSD\r
-        Schema schema = factory.newSchema(new StreamSource(xsdStream));\r
-\r
-        Validator validator = schema.newValidator();\r
-\r
-        return validator;\r
-    }\r
-\r
-    /**\r
-     * Returns the first child element with the given XML local name.\r
-     * If xmlLocalName is null, returns the very first child element.\r
-     */\r
-    private Node getFirstChild(Node node, String xmlLocalName) {\r
-\r
-        for(Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {\r
-            if (child.getNodeType() == Node.ELEMENT_NODE &&\r
-                    SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI())) {\r
-                if (xmlLocalName == null || child.getLocalName().equals(xmlLocalName)) {\r
-                    return child;\r
                 }\r
             }\r
         }\r
-\r
         return null;\r
     }\r
-\r
-    /**\r
-     * Takes an XML document as a string as parameter and returns a DOM for it.\r
-     */\r
-    private Document getDocument(String xml)\r
-            throws ParserConfigurationException, SAXException, IOException {\r
-        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\r
-        factory.setIgnoringComments(true);\r
-        factory.setNamespaceAware(true);\r
-\r
-        DocumentBuilder builder = factory.newDocumentBuilder();\r
-        Document doc = builder.parse(new InputSource(new StringReader(xml)));\r
-\r
-        return doc;\r
-    }\r
 }\r
index 0e11ef5..b28043a 100755 (executable)
@@ -26,6 +26,7 @@ import org.w3c.dom.Node;
 import java.io.File;\r
 import java.util.ArrayList;\r
 import java.util.Map;\r
+import java.util.Properties;\r
 \r
 /**\r
  * A {@link Package} is the base class for "something" that can be downloaded from\r
@@ -41,6 +42,12 @@ import java.util.Map;
  */\r
 public abstract class Package implements IDescription {\r
 \r
+    private static final String PROP_REVISION    = "Pkg.Revision";     //$NON-NLS-1$\r
+    private static final String PROP_LICENSE     = "Pkg.License";      //$NON-NLS-1$\r
+    private static final String PROP_DESC        = "Pkg.Desc";         //$NON-NLS-1$\r
+    private static final String PROP_DESC_URL    = "Pkg.DescUrl";      //$NON-NLS-1$\r
+    private static final String PROP_SOURCE_URL  = "Pkg.SourceUrl";    //$NON-NLS-1$\r
+    private static final String PROP_USER_SOURCE = "Pkg.UserSrc";      //$NON-NLS-1$\r
     private final int mRevision;\r
     private final String mLicense;\r
     private final String mDescription;\r
@@ -68,8 +75,12 @@ public abstract class Package implements IDescription {
      * Manually create a new package with one archive and the given attributes.\r
      * This is used to create packages from local directories in which case there must be\r
      * one archive which URL is the actual target location.\r
+     *\r
+     * Properties from props are used first when possible, e.g. if props is non null.\r
      */\r
-    public Package(RepoSource source,\r
+    public Package(\r
+            RepoSource source,\r
+            Properties props,\r
             int revision,\r
             String license,\r
             String description,\r
@@ -77,19 +88,59 @@ public abstract class Package implements IDescription {
             Os archiveOs,\r
             Arch archiveArch,\r
             String archiveOsPath) {\r
+\r
+        mRevision = Integer.parseInt(getProperty(props, PROP_REVISION, Integer.toString(revision)));\r
+        mLicense     = getProperty(props, PROP_LICENSE,  license);\r
+        mDescription = getProperty(props, PROP_DESC,     description);\r
+        mDescUrl     = getProperty(props, PROP_DESC_URL, descUrl);\r
+\r
+        // If source is null and we can find a source URL in the properties, generate\r
+        // a dummy source just to store the URL. This allows us to easily remember where\r
+        // a package comes from.\r
+        String srcUrl = getProperty(props, PROP_SOURCE_URL, null);\r
+        if (props != null && source == null && srcUrl != null) {\r
+            boolean isUser = Boolean.parseBoolean(props.getProperty(PROP_USER_SOURCE,\r
+                                                                    Boolean.TRUE.toString()));\r
+            source = new RepoSource(srcUrl, isUser);\r
+        }\r
         mSource = source;\r
-        mRevision = revision;\r
-        mLicense = license;\r
-        mDescription = description;\r
-        mDescUrl = descUrl;\r
+\r
         mArchives = new Archive[1];\r
         mArchives[0] = new Archive(this,\r
+                props,\r
                 archiveOs,\r
                 archiveArch,\r
                 archiveOsPath);\r
     }\r
 \r
     /**\r
+     * Utility method that returns a property from a {@link Properties} object.\r
+     * Returns the default value if props is null or if the property is not defined.\r
+     */\r
+    protected String getProperty(Properties props, String propKey, String defaultValue) {\r
+        if (props == null) {\r
+            return defaultValue;\r
+        }\r
+        return props.getProperty(propKey, defaultValue);\r
+    }\r
+\r
+    /**\r
+     * Save the properties of the current packages in the given {@link Properties} object.\r
+     * These properties will later be give the constructor that takes a {@link Properties} object.\r
+     */\r
+    void saveProperties(Properties props) {\r
+        props.setProperty(PROP_REVISION, Integer.toString(mRevision));\r
+        props.setProperty(PROP_LICENSE, mLicense);\r
+        props.setProperty(PROP_DESC, mDescription);\r
+        props.setProperty(PROP_DESC_URL, mDescUrl);\r
+\r
+        if (mSource != null) {\r
+            props.setProperty(PROP_SOURCE_URL,  mSource.getUrl());\r
+            props.setProperty(PROP_USER_SOURCE, Boolean.toString(mSource.isUserSource()));\r
+        }\r
+    }\r
+\r
+    /**\r
      * Parses the uses-licence node of this package, if any, and returns the license\r
      * definition if there's one. Returns null if there's no uses-license element or no\r
      * license of this name defined.\r
index 85dbbd0..1c0a638 100755 (executable)
@@ -27,12 +27,16 @@ import org.w3c.dom.Node;
 \r
 import java.io.File;\r
 import java.util.Map;\r
+import java.util.Properties;\r
 \r
 /**\r
  * Represents a platform XML node in an SDK repository.\r
  */\r
 public class PlatformPackage extends Package {\r
 \r
+    private static final String PROP_API_LEVEL = "Platform.ApiLevel";  //$NON-NLS-1$\r
+    private static final String PROP_VERSION   = "Platform.Version";   //$NON-NLS-1$\r
+\r
     private final String mVersion;\r
     private final int mApiLevel;\r
 \r
@@ -53,8 +57,9 @@ public class PlatformPackage extends Package {
      * This is used to list local SDK folders in which case there is one archive which\r
      * URL is the actual target location.\r
      */\r
-    PlatformPackage(IAndroidTarget target) {\r
+    PlatformPackage(IAndroidTarget target, Properties props) {\r
         super(  null,                       //source\r
+                props,                      //properties\r
                 0,                          //revision\r
                 null,                       //license\r
                 target.getDescription(),    //description\r
@@ -68,6 +73,18 @@ public class PlatformPackage extends Package {
         mVersion  = target.getApiVersionName();\r
     }\r
 \r
+    /**\r
+     * Save the properties of the current packages in the given {@link Properties} object.\r
+     * These properties will later be give the constructor that takes a {@link Properties} object.\r
+     */\r
+    @Override\r
+    void saveProperties(Properties props) {\r
+        super.saveProperties(props);\r
+\r
+        props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));\r
+        props.setProperty(PROP_VERSION, mVersion);\r
+    }\r
+\r
     /** Returns the version, a string, for platform packages. */\r
     public String getVersion() {\r
         return mVersion;\r
index 1076049..b81d044 100755 (executable)
@@ -25,6 +25,7 @@ import org.w3c.dom.Node;
 \r
 import java.io.File;\r
 import java.util.Map;\r
+import java.util.Properties;\r
 \r
 /**\r
  * Represents a tool XML node in an SDK repository.\r
@@ -41,11 +42,13 @@ public class ToolPackage extends Package {
     }\r
 \r
     /**\r
-     * Manually create a new package with one archive and the given attributes.\r
+     * Manually create a new package with one archive and the given attributes or properties.\r
      * This is used to create packages from local directories in which case there must be\r
      * one archive which URL is the actual target location.\r
      */\r
-    ToolPackage(RepoSource source,\r
+    ToolPackage(\r
+            RepoSource source,\r
+            Properties props,\r
             int revision,\r
             String license,\r
             String description,\r
@@ -54,6 +57,7 @@ public class ToolPackage extends Package {
             Arch archiveArch,\r
             String archiveOsPath) {\r
         super(source,\r
+                props,\r
                 revision,\r
                 license,\r
                 description,\r
index a92129f..ab384b8 100755 (executable)
@@ -101,8 +101,10 @@ class LocalSdkAdapter  {
 \r
                 if (packages == null) {\r
                     // load on demand the first time\r
-                    packages = parser.parseSdk(mUpdaterData.getOsSdkRoot(),\r
-                            mUpdaterData.getSdkManager());\r
+                    packages = parser.parseSdk(\r
+                            mUpdaterData.getOsSdkRoot(),\r
+                            mUpdaterData.getSdkManager(),\r
+                            mUpdaterData.getSdkLog());\r
                 }\r
 \r
                 if (packages != null) {\r