| /* |
| * 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; |
| |
| import com.android.SdkConstants; |
| import com.android.annotations.NonNull; |
| import com.android.io.FileWrapper; |
| import com.android.sdklib.IAndroidTarget; |
| import com.android.sdklib.ISystemImage; |
| import com.android.sdklib.ISystemImage.LocationType; |
| import com.android.sdklib.SdkManager; |
| import com.android.sdklib.internal.androidTarget.PlatformTarget; |
| import com.android.sdklib.internal.project.ProjectProperties; |
| import com.android.sdklib.internal.repository.packages.AddonPackage; |
| import com.android.sdklib.internal.repository.packages.BuildToolPackage; |
| import com.android.sdklib.internal.repository.packages.DocPackage; |
| import com.android.sdklib.internal.repository.packages.ExtraPackage; |
| import com.android.sdklib.internal.repository.packages.Package; |
| import com.android.sdklib.internal.repository.packages.PlatformPackage; |
| import com.android.sdklib.internal.repository.packages.PlatformToolPackage; |
| import com.android.sdklib.internal.repository.packages.SamplePackage; |
| import com.android.sdklib.internal.repository.packages.SourcePackage; |
| import com.android.sdklib.internal.repository.packages.SystemImagePackage; |
| import com.android.sdklib.internal.repository.packages.ToolPackage; |
| import com.android.sdklib.io.FileOp; |
| import com.android.sdklib.repository.AddonManifestIniProps; |
| import com.android.sdklib.repository.descriptors.PkgType; |
| import com.android.utils.ILogger; |
| import com.android.utils.Pair; |
| import com.google.common.collect.Lists; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| /** |
| * Scans a local SDK to find which packages are currently installed. |
| * |
| * @deprecated |
| * com.android.sdklib.internal.repository has moved into Studio as |
| * com.android.tools.idea.sdk.remote.internal. |
| */ |
| @Deprecated |
| public class LocalSdkParser { |
| |
| private Package[] mPackages; |
| |
| /** Parse all SDK folders. */ |
| public static final int PARSE_ALL = PkgType.PKG_ALL_INT; |
| /** Parse the SDK/tools folder. */ |
| public static final int PARSE_TOOLS = PkgType.PKG_TOOLS.getIntValue(); |
| /** Parse the SDK/platform-tools folder */ |
| public static final int PARSE_PLATFORM_TOOLS = PkgType.PKG_PLATFORM_TOOLS.getIntValue(); |
| /** Parse the SDK/docs folder. */ |
| public static final int PARSE_DOCS = PkgType.PKG_DOC.getIntValue(); |
| /** |
| * Equivalent to parsing the SDK/platforms folder but does so |
| * by using the <em>valid</em> targets loaded by the {@link SdkManager}. |
| * Parsing the platforms also parses the SDK/system-images folder. |
| */ |
| public static final int PARSE_PLATFORMS = PkgType.PKG_PLATFORM.getIntValue(); |
| /** |
| * Equivalent to parsing the SDK/addons folder but does so |
| * by using the <em>valid</em> targets loaded by the {@link SdkManager}. |
| */ |
| public static final int PARSE_ADDONS = PkgType.PKG_ADDON.getIntValue(); |
| /** Parse the SDK/samples folder. |
| * Note: this will not detect samples located in the SDK/extras packages. */ |
| public static final int PARSE_SAMPLES = PkgType.PKG_SAMPLE.getIntValue(); |
| /** Parse the SDK/sources folder. */ |
| public static final int PARSE_SOURCES = PkgType.PKG_SOURCE.getIntValue(); |
| /** Parse the SDK/extras folder. */ |
| public static final int PARSE_EXTRAS = PkgType.PKG_EXTRA.getIntValue(); |
| /** Parse the SDK/build-tools folder. */ |
| public static final int PARSE_BUILD_TOOLS = PkgType.PKG_BUILD_TOOLS.getIntValue(); |
| |
| public LocalSdkParser() { |
| // pass |
| } |
| |
| /** |
| * Returns the packages found by the last call to {@link #parseSdk}. |
| * <p/> |
| * This returns initially returns null. |
| * Once the parseSdk() method has been called, this returns a possibly empty but non-null array. |
| */ |
| public Package[] getPackages() { |
| return mPackages; |
| } |
| |
| /** |
| * Clear the internal packages list. After this call, {@link #getPackages()} will return |
| * null till {@link #parseSdk} is called. |
| */ |
| public void clearPackages() { |
| mPackages = null; |
| } |
| |
| /** |
| * Scan the give SDK to find all the packages already installed at this location. |
| * <p/> |
| * Store the packages internally. You can use {@link #getPackages()} to retrieve them |
| * at any time later. |
| * <p/> |
| * Equivalent to calling {@code parseSdk(..., PARSE_ALL, ...); } |
| * |
| * @param osSdkRoot The path to the SDK folder, typically {@code sdkManager.getLocation()}. |
| * @param sdkManager An existing SDK manager to list current platforms and addons. |
| * @param monitor A monitor to track progress. Cannot be null. |
| * @return The packages found. Can be retrieved later using {@link #getPackages()}. |
| */ |
| @NonNull |
| public Package[] parseSdk( |
| @NonNull String osSdkRoot, |
| @NonNull SdkManager sdkManager, |
| @NonNull ITaskMonitor monitor) { |
| return parseSdk(osSdkRoot, sdkManager, PARSE_ALL, monitor); |
| } |
| |
| /** |
| * Scan the give SDK to find all the packages already installed at this location. |
| * <p/> |
| * Store the packages internally. You can use {@link #getPackages()} to retrieve them |
| * at any time later. |
| * |
| * @param osSdkRoot The path to the SDK folder, typically {@code sdkManager.getLocation()}. |
| * @param sdkManager An existing SDK manager to list current platforms and addons. |
| * @param parseFilter Either {@link #PARSE_ALL} or an ORed combination of the other |
| * {@code PARSE_} constants to indicate what should be parsed. |
| * @param monitor A monitor to track progress. Cannot be null. |
| * @return The packages found. Can be retrieved later using {@link #getPackages()}. |
| */ |
| @NonNull |
| public Package[] parseSdk( |
| @NonNull String osSdkRoot, |
| @NonNull SdkManager sdkManager, |
| int parseFilter, |
| @NonNull ITaskMonitor monitor) { |
| ArrayList<Package> packages = new ArrayList<Package>(); |
| HashSet<File> visited = new HashSet<File>(); |
| |
| monitor.setProgressMax(11); |
| |
| File dir = null; |
| Package pkg = null; |
| |
| if ((parseFilter & PARSE_DOCS) != 0) { |
| dir = new File(osSdkRoot, SdkConstants.FD_DOCS); |
| pkg = scanDoc(dir, monitor); |
| if (pkg != null) { |
| packages.add(pkg); |
| visited.add(dir); |
| } |
| } |
| monitor.incProgress(1); |
| |
| if ((parseFilter & PARSE_TOOLS) != 0) { |
| dir = new File(osSdkRoot, SdkConstants.FD_TOOLS); |
| pkg = scanTools(dir, monitor); |
| if (pkg != null) { |
| packages.add(pkg); |
| visited.add(dir); |
| } |
| } |
| monitor.incProgress(1); |
| |
| if ((parseFilter & PARSE_PLATFORM_TOOLS) != 0) { |
| dir = new File(osSdkRoot, SdkConstants.FD_PLATFORM_TOOLS); |
| pkg = scanPlatformTools(dir, monitor); |
| if (pkg != null) { |
| packages.add(pkg); |
| visited.add(dir); |
| } |
| } |
| monitor.incProgress(1); |
| |
| if ((parseFilter & PARSE_BUILD_TOOLS) != 0) { |
| scanBuildTools(sdkManager, visited, packages, monitor); |
| } |
| monitor.incProgress(1); |
| |
| // for platforms, add-ons and samples, rely on the SdkManager parser |
| if ((parseFilter & (PARSE_ADDONS | PARSE_PLATFORMS)) != 0) { |
| File samplesRoot = new File(osSdkRoot, SdkConstants.FD_SAMPLES); |
| |
| for(IAndroidTarget target : sdkManager.getTargets()) { |
| Properties props = parseProperties(new File(target.getLocation(), |
| SdkConstants.FN_SOURCE_PROP)); |
| |
| try { |
| pkg = null; |
| if (target.isPlatform() && (parseFilter & PARSE_PLATFORMS) != 0) { |
| pkg = PlatformPackage.create(target, props); |
| |
| if (samplesRoot.isDirectory()) { |
| // Get the samples dir for a platform if it is located in the new |
| // root /samples dir. We purposely ignore "old" samples that are |
| // located under the platform dir. |
| File samplesDir = new File(target.getPath(IAndroidTarget.SAMPLES)); |
| if (samplesDir.exists() && |
| samplesDir.getParentFile().equals(samplesRoot)) { |
| Properties samplesProps = parseProperties( |
| new File(samplesDir, SdkConstants.FN_SOURCE_PROP)); |
| if (samplesProps != null) { |
| Package pkg2 = SamplePackage.create(target, samplesProps); |
| packages.add(pkg2); |
| } |
| visited.add(samplesDir); |
| } |
| } |
| } else if ((parseFilter & PARSE_ADDONS) != 0) { |
| pkg = AddonPackage.create(target, props); |
| } |
| |
| if (pkg != null) { |
| for (ISystemImage systemImage : target.getSystemImages()) { |
| if (systemImage.getLocationType() == LocationType.IN_SYSTEM_IMAGE) { |
| File siDir = systemImage.getLocation(); |
| if (siDir.isDirectory()) { |
| Properties siProps = parseProperties( |
| new File(siDir, SdkConstants.FN_SOURCE_PROP)); |
| Package pkg2 = new SystemImagePackage( |
| target.getVersion(), |
| 0 /*rev*/, // use the one from siProps |
| systemImage.getAbiType(), |
| siProps, |
| siDir.getAbsolutePath()); |
| packages.add(pkg2); |
| visited.add(siDir); |
| } |
| } |
| } |
| } |
| |
| } catch (Exception e) { |
| monitor.error(e, null); |
| } |
| |
| if (pkg != null) { |
| packages.add(pkg); |
| visited.add(new File(target.getLocation())); |
| } |
| } |
| } |
| monitor.incProgress(1); |
| |
| if ((parseFilter & PARSE_PLATFORMS) != 0) { |
| scanMissingSystemImages(sdkManager, visited, packages, monitor); |
| } |
| monitor.incProgress(1); |
| if ((parseFilter & PARSE_ADDONS) != 0) { |
| scanMissingAddons(sdkManager, visited, packages, monitor); |
| } |
| monitor.incProgress(1); |
| if ((parseFilter & PARSE_SAMPLES) != 0) { |
| scanMissingSamples(sdkManager, visited, packages, monitor); |
| } |
| monitor.incProgress(1); |
| if ((parseFilter & PARSE_EXTRAS) != 0) { |
| scanExtras(sdkManager, visited, packages, monitor); |
| } |
| monitor.incProgress(1); |
| if ((parseFilter & PARSE_EXTRAS) != 0) { |
| scanExtrasDirectory(osSdkRoot, visited, packages, monitor); |
| } |
| monitor.incProgress(1); |
| if ((parseFilter & PARSE_SOURCES) != 0) { |
| scanSources(sdkManager, visited, packages, monitor); |
| } |
| monitor.incProgress(1); |
| |
| Collections.sort(packages); |
| |
| mPackages = packages.toArray(new Package[packages.size()]); |
| return mPackages; |
| } |
| |
| /** |
| * Find any directory in the /extras/vendors/path folders for extra packages. |
| * This isn't a recursive search. |
| */ |
| private void scanExtras(SdkManager sdkManager, |
| HashSet<File> visited, |
| ArrayList<Package> packages, |
| ILogger log) { |
| File root = new File(sdkManager.getLocation(), SdkConstants.FD_EXTRAS); |
| |
| for (File vendor : listFilesNonNull(root)) { |
| if (vendor.isDirectory()) { |
| scanExtrasDirectory(vendor.getAbsolutePath(), visited, packages, log); |
| } |
| } |
| } |
| |
| /** |
| * Find any other directory in the given "root" directory that hasn't been visited yet |
| * and assume they contain extra packages. This is <em>not</em> a recursive search. |
| */ |
| private void scanExtrasDirectory(String extrasRoot, |
| HashSet<File> visited, |
| ArrayList<Package> packages, |
| ILogger log) { |
| File root = new File(extrasRoot); |
| |
| for (File dir : listFilesNonNull(root)) { |
| if (dir.isDirectory() && !visited.contains(dir)) { |
| Properties props = parseProperties(new File(dir, SdkConstants.FN_SOURCE_PROP)); |
| if (props != null) { |
| try { |
| Package pkg = ExtraPackage.create( |
| null, //source |
| props, //properties |
| null, //vendor |
| dir.getName(), //path |
| 0, //revision |
| null, //license |
| null, //description |
| null, //descUrl |
| dir.getPath() //archiveOsPath |
| ); |
| |
| packages.add(pkg); |
| visited.add(dir); |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Find any other sub-directories under the /samples root that hasn't been visited yet |
| * and assume they contain sample packages. This is <em>not</em> a recursive search. |
| * <p/> |
| * The use case is to find samples dirs under /samples when their target isn't loaded. |
| */ |
| private void scanMissingSamples(SdkManager sdkManager, |
| HashSet<File> visited, |
| ArrayList<Package> packages, |
| ILogger log) { |
| File root = new File(sdkManager.getLocation()); |
| root = new File(root, SdkConstants.FD_SAMPLES); |
| |
| for (File dir : listFilesNonNull(root)) { |
| if (dir.isDirectory() && !visited.contains(dir)) { |
| Properties props = parseProperties(new File(dir, SdkConstants.FN_SOURCE_PROP)); |
| if (props != null) { |
| try { |
| Package pkg = SamplePackage.create(dir.getAbsolutePath(), props); |
| packages.add(pkg); |
| visited.add(dir); |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * The sdk manager only lists valid addons. However here we also want to find "broken" |
| * addons, i.e. addons that failed to load for some reason. |
| * <p/> |
| * Find any other sub-directories under the /add-ons root that hasn't been visited yet |
| * and assume they contain broken addons. |
| */ |
| private void scanMissingAddons(SdkManager sdkManager, |
| HashSet<File> visited, |
| ArrayList<Package> packages, |
| ILogger log) { |
| File addons = new File(new File(sdkManager.getLocation()), SdkConstants.FD_ADDONS); |
| |
| for (File dir : listFilesNonNull(addons)) { |
| if (dir.isDirectory() && !visited.contains(dir)) { |
| Pair<Map<String, String>, String> infos = |
| parseAddonProperties(dir, sdkManager.getTargets(), log); |
| Properties sourceProps = |
| parseProperties(new File(dir, SdkConstants.FN_SOURCE_PROP)); |
| |
| Map<String, String> addonProps = infos.getFirst(); |
| String error = infos.getSecond(); |
| try { |
| Package pkg = AddonPackage.createBroken(dir.getAbsolutePath(), |
| sourceProps, |
| addonProps, |
| error); |
| packages.add(pkg); |
| visited.add(dir); |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Parses the add-on properties and decodes any error that occurs when |
| * loading an addon. |
| * |
| * @param addonDir the location of the addon directory. |
| * @param targetList The list of Android target that were already loaded |
| * from the SDK. |
| * @param log the ILogger object receiving warning/error from the parsing. |
| * @return A pair with the property map and an error string. Both can be |
| * null but not at the same time. If a non-null error is present |
| * then the property map must be ignored. The error should be |
| * translatable as it might show up in the SdkManager UI. |
| */ |
| @Deprecated // Copied from SdkManager.java, dup of LocalAddonPkgInfo.parseAddonProperties. |
| @NonNull |
| public static Pair<Map<String, String>, String> parseAddonProperties( |
| @NonNull File addonDir, @NonNull IAndroidTarget[] targetList, |
| @NonNull ILogger log) { |
| Map<String, String> propertyMap = null; |
| String error = null; |
| |
| FileWrapper addOnManifest = new FileWrapper(addonDir, |
| SdkConstants.FN_MANIFEST_INI); |
| |
| do { |
| if (!addOnManifest.isFile()) { |
| error = String.format("File not found: %1$s", |
| SdkConstants.FN_MANIFEST_INI); |
| break; |
| } |
| |
| propertyMap = ProjectProperties.parsePropertyFile(addOnManifest, |
| log); |
| if (propertyMap == null) { |
| error = String.format("Failed to parse properties from %1$s", |
| SdkConstants.FN_MANIFEST_INI); |
| break; |
| } |
| |
| // look for some specific values in the map. |
| // we require name, vendor, and api |
| String name = propertyMap.get(AddonManifestIniProps.ADDON_NAME); |
| if (name == null) { |
| error = String.format("'%1$s' is missing from %2$s.", |
| AddonManifestIniProps.ADDON_NAME, |
| SdkConstants.FN_MANIFEST_INI); |
| break; |
| } |
| |
| String vendor = propertyMap.get(AddonManifestIniProps.ADDON_VENDOR); |
| if (vendor == null) { |
| error = String.format("'%1$s' is missing from %2$s.", |
| AddonManifestIniProps.ADDON_VENDOR, |
| SdkConstants.FN_MANIFEST_INI); |
| break; |
| } |
| |
| String api = propertyMap.get(AddonManifestIniProps.ADDON_API); |
| if (api == null) { |
| error = String.format("'%1$s' is missing from %2$s.", |
| AddonManifestIniProps.ADDON_API, |
| SdkConstants.FN_MANIFEST_INI); |
| break; |
| } |
| |
| // Look for a platform that has a matching api level or codename. |
| PlatformTarget baseTarget = null; |
| for (IAndroidTarget target : targetList) { |
| if (target.isPlatform() && target.getVersion().equals(api)) { |
| baseTarget = (PlatformTarget) target; |
| break; |
| } |
| } |
| |
| if (baseTarget == null) { |
| error = String.format( |
| "Unable to find base platform with API level '%1$s'", |
| api); |
| break; |
| } |
| |
| // get the add-on revision |
| String revision = propertyMap.get(AddonManifestIniProps.ADDON_REVISION); |
| if (revision == null) { |
| revision = propertyMap.get(AddonManifestIniProps.ADDON_REVISION_OLD); |
| } |
| if (revision != null) { |
| try { |
| Integer.parseInt(revision); |
| } catch (NumberFormatException e) { |
| // looks like revision does not parse to a number. |
| error = String.format( |
| "%1$s is not a valid number in %2$s.", |
| AddonManifestIniProps.ADDON_REVISION, |
| SdkConstants.FN_BUILD_PROP); |
| break; |
| } |
| } |
| |
| } while (false); |
| |
| return Pair.of(propertyMap, error); |
| } |
| |
| |
| /** |
| * The sdk manager only lists valid system image via its addons or platform targets. |
| * However here we also want to find "broken" system images, that is system images |
| * that are located in the sdk/system-images folder but somehow not loaded properly. |
| */ |
| private void scanMissingSystemImages(SdkManager sdkManager, |
| HashSet<File> visited, |
| ArrayList<Package> packages, |
| ILogger log) { |
| File siRoot = new File(sdkManager.getLocation(), SdkConstants.FD_SYSTEM_IMAGES); |
| |
| // The system-images folder contains a list of platform folders. |
| for (File platformDir : listFilesNonNull(siRoot)) { |
| if (platformDir.isDirectory() && !visited.contains(platformDir)) { |
| visited.add(platformDir); |
| |
| // In the platform directory, we expect a list of abi folders |
| // or a list of tag/abi folders. Basically parse any folder that has |
| // a source.prop file within 2 levels. |
| List<File> propFiles = Lists.newArrayList(); |
| |
| for (File dir1 : listFilesNonNull(platformDir)) { |
| if (dir1.isDirectory() && !visited.contains(dir1)) { |
| visited.add(dir1); |
| File prop1 = new File(dir1, SdkConstants.FN_SOURCE_PROP); |
| if (prop1.isFile()) { |
| propFiles.add(prop1); |
| } else { |
| for (File dir2 : listFilesNonNull(dir1)) { |
| if (dir2.isDirectory() && !visited.contains(dir2)) { |
| visited.add(dir2); |
| File prop2 = new File(dir2, SdkConstants.FN_SOURCE_PROP); |
| if (prop2.isFile()) { |
| propFiles.add(prop2); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| for (File propFile : propFiles) { |
| Properties props = parseProperties(propFile); |
| try { |
| Package pkg = SystemImagePackage.createBroken(propFile.getParentFile(), |
| props); |
| packages.add(pkg); |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Scan the sources/folders and register valid as well as broken source packages. |
| */ |
| private void scanSources(SdkManager sdkManager, |
| HashSet<File> visited, |
| ArrayList<Package> packages, |
| ILogger log) { |
| File srcRoot = new File(sdkManager.getLocation(), SdkConstants.FD_PKG_SOURCES); |
| |
| // The sources folder contains a list of platform folders. |
| for (File platformDir : listFilesNonNull(srcRoot)) { |
| if (platformDir.isDirectory() && !visited.contains(platformDir)) { |
| visited.add(platformDir); |
| |
| // Ignore empty directories |
| File[] srcFiles = platformDir.listFiles(); |
| if (srcFiles != null && srcFiles.length > 0) { |
| Properties props = |
| parseProperties(new File(platformDir, SdkConstants.FN_SOURCE_PROP)); |
| |
| try { |
| Package pkg = SourcePackage.create(platformDir, props); |
| packages.add(pkg); |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Try to find a tools package at the given location. |
| * Returns null if not found. |
| */ |
| private Package scanTools(File toolFolder, ILogger log) { |
| // Can we find some properties? |
| Properties props = parseProperties(new File(toolFolder, SdkConstants.FN_SOURCE_PROP)); |
| |
| // We're not going to check that all tools are present. At the very least |
| // we should expect to find android and an emulator adapted to the current OS. |
| boolean hasEmulator = false; |
| boolean hasAndroid = false; |
| String android1 = SdkConstants.androidCmdName().replace(".bat", ".exe"); |
| String android2 = android1.indexOf('.') == -1 ? null : android1.replace(".exe", ".bat"); |
| for (File file : listFilesNonNull(toolFolder)) { |
| String name = file.getName(); |
| if (SdkConstants.FN_EMULATOR.equals(name)) { |
| hasEmulator = true; |
| } |
| if (android1.equals(name) || (android2 != null && android2.equals(name))) { |
| hasAndroid = true; |
| } |
| } |
| |
| if (!hasAndroid || !hasEmulator) { |
| return null; |
| } |
| |
| // Create our package. use the properties if we found any. |
| try { |
| Package pkg = ToolPackage.create( |
| null, //source |
| props, //properties |
| 0, //revision |
| null, //license |
| "Tools", //description |
| null, //descUrl |
| toolFolder.getPath() //archiveOsPath |
| ); |
| |
| return pkg; |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| return null; |
| } |
| |
| /** |
| * Try to find a platform-tools package at the given location. |
| * Returns null if not found. |
| */ |
| private Package scanPlatformTools(File platformToolsFolder, ILogger log) { |
| // Can we find some properties? |
| Properties props = parseProperties(new File(platformToolsFolder, |
| SdkConstants.FN_SOURCE_PROP)); |
| |
| // We're not going to check that all tools are present. At the very least |
| // we should expect to find adb, aidl, aapt and dx (adapted to the current OS). |
| |
| if (platformToolsFolder.listFiles() == null) { |
| // ListFiles is null if the directory doesn't even exist. |
| // Not going to find anything in there... |
| return null; |
| } |
| |
| // Create our package. use the properties if we found any. |
| try { |
| Package pkg = PlatformToolPackage.create( |
| null, //source |
| props, //properties |
| 0, //revision |
| null, //license |
| "Platform Tools", //description |
| null, //descUrl |
| platformToolsFolder.getPath() //archiveOsPath |
| ); |
| |
| return pkg; |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| return null; |
| } |
| |
| /** |
| * Scan the build-tool/folders and register valid as well as broken build tool packages. |
| */ |
| private void scanBuildTools( |
| SdkManager sdkManager, |
| HashSet<File> visited, |
| ArrayList<Package> packages, |
| ILogger log) { |
| File buildToolRoot = new File(sdkManager.getLocation(), SdkConstants.FD_BUILD_TOOLS); |
| |
| // The build-tool root folder contains a list of revisioned folders. |
| for (File buildToolDir : listFilesNonNull(buildToolRoot)) { |
| if (buildToolDir.isDirectory() && !visited.contains(buildToolDir)) { |
| visited.add(buildToolDir); |
| |
| // Ignore empty directories |
| File[] srcFiles = buildToolDir.listFiles(); |
| if (srcFiles != null && srcFiles.length > 0) { |
| Properties props = |
| parseProperties(new File(buildToolDir, SdkConstants.FN_SOURCE_PROP)); |
| |
| try { |
| Package pkg = BuildToolPackage.create(buildToolDir, props); |
| packages.add(pkg); |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Try to find a docs package at the given location. |
| * Returns null if not found. |
| */ |
| private Package scanDoc(File docFolder, ILogger log) { |
| // Can we find some properties? |
| Properties props = parseProperties(new File(docFolder, SdkConstants.FN_SOURCE_PROP)); |
| |
| // To start with, a doc folder should have an "index.html" to be acceptable. |
| // We don't actually check the content of the file. |
| if (new File(docFolder, "index.html").isFile()) { |
| try { |
| Package pkg = DocPackage.create( |
| null, //source |
| props, //properties |
| 0, //apiLevel |
| null, //codename |
| 0, //revision |
| null, //license |
| null, //description |
| null, //descUrl |
| docFolder.getPath() //archiveOsPath |
| ); |
| |
| return pkg; |
| } catch (Exception e) { |
| log.error(e, null); |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Parses the given file as properties file if it exists. |
| * Returns null if the file does not exist, cannot be parsed or has no properties. |
| */ |
| private Properties parseProperties(File propsFile) { |
| FileInputStream fis = null; |
| try { |
| if (propsFile.exists()) { |
| fis = new FileInputStream(propsFile); |
| |
| Properties props = new Properties(); |
| props.load(fis); |
| |
| // To be valid, there must be at least one property in it. |
| if (props.size() > 0) { |
| return props; |
| } |
| } |
| |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } finally { |
| if (fis != null) { |
| try { |
| fis.close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Helper method that calls {@link File#listFiles()} and returns |
| * a non-null empty list if the input is not a directory or has |
| * no files. |
| */ |
| @NonNull |
| private static File[] listFilesNonNull(@NonNull File dir) { |
| if (dir.isDirectory()) { |
| File[] files = dir.listFiles(); |
| if (files != null) { |
| return files; |
| } |
| } |
| return FileOp.EMPTY_FILE_ARRAY; |
| } |
| } |