OSDN Git Service

3c7b8c68e303e19154656948cd05a79139891ea9
[android-x86/sdk.git] / sdkmanager / libs / sdklib / src / com / android / sdklib / internal / repository / AddonPackage.java
1 /*\r
2  * Copyright (C) 2009 The Android Open Source Project\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 package com.android.sdklib.internal.repository;\r
18 \r
19 import com.android.sdklib.AndroidVersion;\r
20 import com.android.sdklib.IAndroidTarget;\r
21 import com.android.sdklib.SdkConstants;\r
22 import com.android.sdklib.SdkManager;\r
23 import com.android.sdklib.IAndroidTarget.IOptionalLibrary;\r
24 import com.android.sdklib.internal.repository.Archive.Arch;\r
25 import com.android.sdklib.internal.repository.Archive.Os;\r
26 import com.android.sdklib.repository.SdkRepository;\r
27 \r
28 import org.w3c.dom.Node;\r
29 \r
30 import java.io.File;\r
31 import java.util.ArrayList;\r
32 import java.util.Map;\r
33 import java.util.Properties;\r
34 \r
35 /**\r
36  * Represents an add-on XML node in an SDK repository.\r
37  */\r
38 public class AddonPackage extends Package {\r
39 \r
40     private static final String PROP_NAME      = "Addon.Name";      //$NON-NLS-1$\r
41     private static final String PROP_VENDOR    = "Addon.Vendor";    //$NON-NLS-1$\r
42 \r
43     private final String mVendor;\r
44     private final String mName;\r
45     private final AndroidVersion mVersion;\r
46 \r
47     /** An add-on library. */\r
48     public static class Lib {\r
49         private final String mName;\r
50         private final String mDescription;\r
51 \r
52         public Lib(String name, String description) {\r
53             mName = name;\r
54             mDescription = description;\r
55         }\r
56 \r
57         public String getName() {\r
58             return mName;\r
59         }\r
60 \r
61         public String getDescription() {\r
62             return mDescription;\r
63         }\r
64     }\r
65 \r
66     private final Lib[] mLibs;\r
67 \r
68     /**\r
69      * Creates a new add-on package from the attributes and elements of the given XML node.\r
70      * <p/>\r
71      * This constructor should throw an exception if the package cannot be created.\r
72      */\r
73     AddonPackage(RepoSource source, Node packageNode, Map<String,String> licenses) {\r
74         super(source, packageNode, licenses);\r
75         mVendor   = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VENDOR);\r
76         mName     = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_NAME);\r
77         int apiLevel = XmlParserUtils.getXmlInt   (packageNode, SdkRepository.NODE_API_LEVEL, 0);\r
78         String codeName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_CODENAME);\r
79         if (codeName.length() == 0) {\r
80             codeName = null;\r
81         }\r
82         mVersion = new AndroidVersion(apiLevel, codeName);\r
83 \r
84         mLibs = parseLibs(XmlParserUtils.getFirstChild(packageNode, SdkRepository.NODE_LIBS));\r
85     }\r
86 \r
87     /**\r
88      * Creates a new platform package based on an actual {@link IAndroidTarget} (which\r
89      * {@link IAndroidTarget#isPlatform()} false) from the {@link SdkManager}.\r
90      * This is used to list local SDK folders in which case there is one archive which\r
91      * URL is the actual target location.\r
92      */\r
93     AddonPackage(IAndroidTarget target, Properties props) {\r
94         super(  null,                       //source\r
95                 props,                      //properties\r
96                 target.getRevision(),       //revision\r
97                 null,                       //license\r
98                 target.getDescription(),    //description\r
99                 null,                       //descUrl\r
100                 Os.getCurrentOs(),          //archiveOs\r
101                 Arch.getCurrentArch(),      //archiveArch\r
102                 target.getLocation()        //archiveOsPath\r
103                 );\r
104 \r
105         mVersion = target.getVersion();\r
106         mName     = target.getName();\r
107         mVendor   = target.getVendor();\r
108 \r
109         IOptionalLibrary[] optLibs = target.getOptionalLibraries();\r
110         if (optLibs == null || optLibs.length == 0) {\r
111             mLibs = new Lib[0];\r
112         } else {\r
113             mLibs = new Lib[optLibs.length];\r
114             for (int i = 0; i < optLibs.length; i++) {\r
115                 mLibs[i] = new Lib(optLibs[i].getName(), optLibs[i].getDescription());\r
116             }\r
117         }\r
118     }\r
119 \r
120     /**\r
121      * Save the properties of the current packages in the given {@link Properties} object.\r
122      * These properties will later be given to a constructor that takes a {@link Properties} object.\r
123      */\r
124     @Override\r
125     void saveProperties(Properties props) {\r
126         super.saveProperties(props);\r
127 \r
128         mVersion.saveProperties(props);\r
129         if (mName != null) {\r
130             props.setProperty(PROP_NAME, mName);\r
131         }\r
132         if (mVendor != null) {\r
133             props.setProperty(PROP_VENDOR, mVendor);\r
134         }\r
135     }\r
136 \r
137     /**\r
138      * Parses a <libs> element.\r
139      */\r
140     private Lib[] parseLibs(Node libsNode) {\r
141         ArrayList<Lib> libs = new ArrayList<Lib>();\r
142 \r
143         if (libsNode != null) {\r
144             for(Node child = libsNode.getFirstChild();\r
145                 child != null;\r
146                 child = child.getNextSibling()) {\r
147 \r
148                 if (child.getNodeType() == Node.ELEMENT_NODE &&\r
149                         SdkRepository.NS_SDK_REPOSITORY.equals(child.getNamespaceURI()) &&\r
150                         SdkRepository.NODE_LIB.equals(child.getLocalName())) {\r
151                     libs.add(parseLib(child));\r
152                 }\r
153             }\r
154         }\r
155 \r
156         return libs.toArray(new Lib[libs.size()]);\r
157     }\r
158 \r
159     /**\r
160      * Parses a <lib> element from a <libs> container.\r
161      */\r
162     private Lib parseLib(Node libNode) {\r
163         return new Lib(XmlParserUtils.getXmlString(libNode, SdkRepository.NODE_NAME),\r
164                        XmlParserUtils.getXmlString(libNode, SdkRepository.NODE_DESCRIPTION));\r
165     }\r
166 \r
167     /** Returns the vendor, a string, for add-on packages. */\r
168     public String getVendor() {\r
169         return mVendor;\r
170     }\r
171 \r
172     /** Returns the name, a string, for add-on packages or for libraries. */\r
173     public String getName() {\r
174         return mName;\r
175     }\r
176 \r
177     /** Returns the version, for platform, add-on and doc packages. */\r
178     public AndroidVersion getVersion() {\r
179         return mVersion;\r
180     }\r
181 \r
182     /** Returns the libs defined in this add-on. Can be an empty array but not null. */\r
183     public Lib[] getLibs() {\r
184         return mLibs;\r
185     }\r
186 \r
187     /** Returns a short description for an {@link IDescription}. */\r
188     @Override\r
189     public String getShortDescription() {\r
190         return String.format("%1$s by %2$s for Android API %3$s",\r
191                 getName(),\r
192                 getVendor(),\r
193                 mVersion.getApiString());\r
194     }\r
195 \r
196     /** Returns a long description for an {@link IDescription}. */\r
197     @Override\r
198     public String getLongDescription() {\r
199         return String.format("%1$s.\n%2$s",\r
200                 getShortDescription(),\r
201                 super.getLongDescription());\r
202     }\r
203 \r
204     /**\r
205      * Computes a potential installation folder if an archive of this package were\r
206      * to be installed right away in the given SDK root.\r
207      * <p/>\r
208      * An add-on package is typically installed in SDK/add-ons/"addon-name"-"api-level".\r
209      * The name needs to be sanitized to be acceptable as a directory name.\r
210      * However if we can find a different directory under SDK/add-ons that already\r
211      * has this add-ons installed, we'll use that one.\r
212      *\r
213      * @param osSdkRoot The OS path of the SDK root folder.\r
214      * @param suggestedDir A suggestion for the installation folder name, based on the root\r
215      *                     folder used in the zip archive.\r
216      * @param sdkManager An existing SDK manager to list current platforms and addons.\r
217      * @return A new {@link File} corresponding to the directory to use to install this package.\r
218      */\r
219     @Override\r
220     public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {\r
221         File addons = new File(osSdkRoot, SdkConstants.FD_ADDONS);\r
222 \r
223         // First find if this add-on is already installed. If so, reuse the same directory.\r
224         for (IAndroidTarget target : sdkManager.getTargets()) {\r
225             if (!target.isPlatform() &&\r
226                     target.getVersion().equals(mVersion) &&\r
227                     target.getName().equals(getName()) &&\r
228                     target.getVendor().equals(getVendor())) {\r
229                 return new File(target.getLocation());\r
230             }\r
231         }\r
232 \r
233         // Otherwise, see about reusing the suggestedDir. It must not be already used or\r
234         // add some index to it, or we try to make up one.\r
235         String name = suggestedDir;\r
236 \r
237         if (suggestedDir == null || suggestedDir.length() == 0) {\r
238             name = String.format("addon-%s-%s-%s", getName(), getVendor(), //$NON-NLS-1$\r
239                     mVersion.getApiString());\r
240             name = name.toLowerCase();\r
241             name = name.replaceAll("[^a-z0-9_-]+", "_");      //$NON-NLS-1$ //$NON-NLS-2$\r
242             name = name.replaceAll("_+", "_");                //$NON-NLS-1$ //$NON-NLS-2$\r
243         }\r
244 \r
245         for (int i = 0; i < 100; i++) {\r
246             String name2 = i == 0 ? name : String.format("%s-%d", name, i); //$NON-NLS-1$\r
247             File folder = new File(addons, name2);\r
248             if (!folder.exists()) {\r
249                 return folder;\r
250             }\r
251         }\r
252 \r
253         // We shouldn't really get here. I mean, seriously, we tried hard enough.\r
254         return null;\r
255     }\r
256 \r
257     @Override\r
258     public boolean sameItemAs(Package pkg) {\r
259         if (pkg instanceof AddonPackage) {\r
260             AddonPackage newPkg = (AddonPackage)pkg;\r
261 \r
262             // check they are the same add-on.\r
263             return getName().equals(newPkg.getName()) &&\r
264                     getVendor().equals(newPkg.getVendor()) &&\r
265                     getVersion().equals(newPkg.getVersion());\r
266         }\r
267 \r
268         return false;\r
269     }\r
270 }\r