1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.sdklib.internal.repository; 18 19 import com.android.sdklib.IAndroidTarget; 20 import com.android.sdklib.ISdkLog; 21 import com.android.sdklib.SdkConstants; 22 import com.android.sdklib.SdkManager; 23 import com.android.sdklib.internal.repository.Archive.Arch; 24 import com.android.sdklib.internal.repository.Archive.Os; 25 26 import java.io.File; 27 import java.io.FileInputStream; 28 import java.io.IOException; 29 import java.util.ArrayList; 30 import java.util.HashSet; 31 import java.util.Properties; 32 import java.util.Set; 33 34 /** 35 * Scans a local SDK to find which packages are currently installed. 36 */ 37 public class LocalSdkParser { 38 39 static final String SOURCE_PROPERTIES = "source.properties"; //$NON-NLS-1$ 40 private Package[] mPackages; 41 LocalSdkParser()42 public LocalSdkParser() { 43 // pass 44 } 45 46 /** 47 * Returns the packages found by the last call to 48 * {@link #parseSdk(String, SdkManager, ISdkLog)}. 49 * <p/> 50 * This returns initially returns null. 51 * Once the parseSdk() method has been called, this returns a possibly empty but non-null array. 52 */ getPackages()53 public Package[] getPackages() { 54 return mPackages; 55 } 56 57 /** 58 * Clear the internal packages list. After this call, {@link #getPackages()} will return 59 * null till {@link #parseSdk(String, SdkManager, ISdkLog)} is called. 60 */ clearPackages()61 public void clearPackages() { 62 mPackages = null; 63 } 64 65 /** 66 * Scan the give SDK to find all the packages already installed at this location. 67 * <p/> 68 * Store the packages internally. You can use {@link #getPackages()} to retrieve them 69 * at any time later. 70 * 71 * @param osSdkRoot The path to the SDK folder. 72 * @param sdkManager An existing SDK manager to list current platforms and addons. 73 * @param log An SDK logger object. 74 * @return The packages found. Can be retrieved later using {@link #getPackages()}. 75 */ parseSdk(String osSdkRoot, SdkManager sdkManager, ISdkLog log)76 public Package[] parseSdk(String osSdkRoot, SdkManager sdkManager, ISdkLog log) { 77 ArrayList<Package> packages = new ArrayList<Package>(); 78 HashSet<File> visited = new HashSet<File>(); 79 80 File dir = new File(osSdkRoot, SdkConstants.FD_DOCS); 81 Package pkg = scanDoc(dir, log); 82 if (pkg != null) { 83 packages.add(pkg); 84 visited.add(dir); 85 } 86 87 dir = new File(osSdkRoot, SdkConstants.FD_TOOLS); 88 pkg = scanTools(dir, log); 89 if (pkg != null) { 90 packages.add(pkg); 91 visited.add(dir); 92 } 93 94 // for platforms and add-ons, rely on the SdkManager parser 95 for(IAndroidTarget target : sdkManager.getTargets()) { 96 97 Properties props = parseProperties(new File(target.getLocation(), SOURCE_PROPERTIES)); 98 99 try { 100 if (target.isPlatform()) { 101 pkg = new PlatformPackage(target, props); 102 } else { 103 pkg = new AddonPackage(target, props); 104 } 105 } catch (Exception e) { 106 log.error(e, null); 107 } 108 109 if (pkg != null) { 110 packages.add(pkg); 111 visited.add(new File(target.getLocation())); 112 } 113 } 114 115 scanExtra(osSdkRoot, visited, packages, log); 116 117 mPackages = packages.toArray(new Package[packages.size()]); 118 return mPackages; 119 } 120 121 /** 122 * Find any other directory what we haven't successfully visited and 123 * assume they contain extra packages. 124 * @param log 125 */ scanExtra(String osSdkRoot, HashSet<File> visited, ArrayList<Package> packages, ISdkLog log)126 private void scanExtra(String osSdkRoot, 127 HashSet<File> visited, 128 ArrayList<Package> packages, 129 ISdkLog log) { 130 File root = new File(osSdkRoot); 131 for (File dir : root.listFiles()) { 132 if (dir.isDirectory() && !visited.contains(dir)) { 133 134 Properties props = parseProperties(new File(dir, SOURCE_PROPERTIES)); 135 if (props != null) { 136 try { 137 ExtraPackage pkg = new ExtraPackage( 138 null, //source 139 props, //properties 140 dir.getName(), //path 141 0, //revision 142 null, //license 143 "Tools", //description 144 null, //descUrl 145 Os.getCurrentOs(), //archiveOs 146 Arch.getCurrentArch(), //archiveArch 147 dir.getPath() //archiveOsPath 148 ); 149 150 // We only accept this as an extra package if it has a valid local path. 151 if (pkg.isPathValid()) { 152 packages.add(pkg); 153 } 154 } catch (Exception e) { 155 log.error(e, null); 156 } 157 } 158 } 159 } 160 } 161 162 /** 163 * Try to find a tools package at the given location. 164 * Returns null if not found. 165 */ scanTools(File toolFolder, ISdkLog log)166 private Package scanTools(File toolFolder, ISdkLog log) { 167 // Can we find some properties? 168 Properties props = parseProperties(new File(toolFolder, SOURCE_PROPERTIES)); 169 170 // We're not going to check that all tools are present. At the very least 171 // we should expect to find adb, android and an emulator adapted to the current OS. 172 Set<String> names = new HashSet<String>(); 173 for (File file : toolFolder.listFiles()) { 174 names.add(file.getName()); 175 } 176 if (!names.contains(SdkConstants.FN_ADB) || 177 !names.contains(SdkConstants.androidCmdName()) || 178 !names.contains(SdkConstants.FN_EMULATOR)) { 179 return null; 180 } 181 182 // Create are package. use the properties if we found any. 183 try { 184 ToolPackage pkg = new ToolPackage( 185 null, //source 186 props, //properties 187 0, //revision 188 null, //license 189 "Tools", //description 190 null, //descUrl 191 Os.getCurrentOs(), //archiveOs 192 Arch.getCurrentArch(), //archiveArch 193 toolFolder.getPath() //archiveOsPath 194 ); 195 196 return pkg; 197 } catch (Exception e) { 198 log.error(e, null); 199 } 200 return null; 201 } 202 203 /** 204 * Try to find a docs package at the given location. 205 * Returns null if not found. 206 */ scanDoc(File docFolder, ISdkLog log)207 private Package scanDoc(File docFolder, ISdkLog log) { 208 // Can we find some properties? 209 Properties props = parseProperties(new File(docFolder, SOURCE_PROPERTIES)); 210 211 // To start with, a doc folder should have an "index.html" to be acceptable. 212 // We don't actually check the content of the file. 213 if (new File(docFolder, "index.html").isFile()) { 214 try { 215 DocPackage pkg = new DocPackage( 216 null, //source 217 props, //properties 218 0, //apiLevel 219 null, //codename 220 0, //revision 221 null, //license 222 null, //description 223 null, //descUrl 224 Os.getCurrentOs(), //archiveOs 225 Arch.getCurrentArch(), //archiveArch 226 docFolder.getPath() //archiveOsPath 227 ); 228 229 return pkg; 230 } catch (Exception e) { 231 log.error(e, null); 232 } 233 } 234 235 return null; 236 } 237 238 /** 239 * Parses the given file as properties file if it exists. 240 * Returns null if the file does not exist, cannot be parsed or has no properties. 241 */ parseProperties(File propsFile)242 private Properties parseProperties(File propsFile) { 243 FileInputStream fis = null; 244 try { 245 if (propsFile.exists()) { 246 fis = new FileInputStream(propsFile); 247 248 Properties props = new Properties(); 249 props.load(fis); 250 251 // To be valid, there must be at least one property in it. 252 if (props.size() > 0) { 253 return props; 254 } 255 } 256 257 } catch (IOException e) { 258 e.printStackTrace(); 259 } finally { 260 if (fis != null) { 261 try { 262 fis.close(); 263 } catch (IOException e) { 264 } 265 } 266 } 267 return null; 268 } 269 } 270