/// <summary> /// Initialize this instance. /// </summary> /// <param name="toolPath">Path of the android tool.</param> public SdkManager(string toolPath) { this.toolPath = toolPath; var toolsDir = Path.GetDirectoryName(Path.GetDirectoryName(toolPath)); var sdkDir = Path.GetDirectoryName(toolsDir); toolsPackage = AndroidSdkPackage.ReadFromSourceProperties( sdkDir, toolsDir.Substring((sdkDir + Path.PathSeparator).Length)); }
/// <summary> /// Parse "android list sdk -u -e -a" output. /// </summary> private AndroidSdkPackageCollection ParseAndroidListSdkOutput( string androidListSdkOutput) { var packages = new AndroidSdkPackageCollection(); AndroidSdkPackage currentPackage = null; foreach (string line in CommandLine.SplitLines(androidListSdkOutput)) { // Check for the start of a new package entry. if (line.StartsWith("---")) { currentPackage = null; continue; } Match match; // If this is the start of a package description, add a package. match = PACKAGE_ID_REGEX.Match(line); if (match.Success) { // TODO(smiles): Convert the legacy package name to a new package name. currentPackage = new AndroidSdkPackage { LegacyName = match.Groups[1].Value }; packages[currentPackage.Name].Add(currentPackage); continue; } if (currentPackage == null) { continue; } // Add a package description. match = PACKAGE_DESCRIPTION_REGEX.Match(line); if (match.Success) { currentPackage.Description = match.Groups[1].Value; continue; } // Parse the install path and record whether the package is installed. match = PACKAGE_INSTALL_LOCATION_REGEX.Match(line); if (match.Success) { currentPackage.Installed = File.Exists( Path.Combine(Path.Combine(sdkPath, match.Groups[1].Value), "source.properties")); } } return(packages); }
/// <summary> /// Read package metadata from the source.properties file within the specified directory. /// </summary> /// <param name="sdkDirectory">Android SDK directory to query.</param> /// <param name="packageDirectory">Directory containing the package relative to /// sdkDirectory.</param> public static AndroidSdkPackage ReadFromSourceProperties(string sdkDirectory, string packageDirectory) { var propertiesPath = System.IO.Path.Combine( sdkDirectory, System.IO.Path.Combine(packageDirectory, "source.properties")); string propertiesText = null; try { propertiesText = File.ReadAllText(propertiesPath); } catch (Exception e) { PlayServicesResolver.Log(String.Format("Unable to read {0}\n{1}\n", propertiesPath, e.ToString()), level: LogLevel.Verbose); return(null); } // Unfortunately the package name is simply based upon the path within the SDK. var sdkPackage = new AndroidSdkPackage { Path = packageDirectory }; const string VERSION_FIELD_NAME = "Pkg.Revision="; const string DESCRIPTION_FIELD_NAME = "Pkg.Desc="; foreach (var rawLine in CommandLine.SplitLines(propertiesText)) { var line = rawLine.Trim(); // Ignore comments. if (line.StartsWith("#")) { continue; } // Parse fields if (line.StartsWith(VERSION_FIELD_NAME)) { sdkPackage.VersionString = line.Substring(VERSION_FIELD_NAME.Length); } else if (line.StartsWith(DESCRIPTION_FIELD_NAME)) { sdkPackage.Description = line.Substring(DESCRIPTION_FIELD_NAME.Length); } } return(sdkPackage); }
/// <summary> /// Get the most recent available version of a specified package, prefering installed. /// </summary> /// <returns>The package if it's available, null otherwise.</returns> public AndroidSdkPackage GetMostRecentAvailablePackage(string packageName) { var list = this[packageName]; if (list == null || !list.Any()) { return(null); } var maxVersion = list.Max(p => p.Version); AndroidSdkPackage mostRecentPackage = null; foreach (var package in list) { if (package.Version == maxVersion && (mostRecentPackage == null || !mostRecentPackage.Installed)) { mostRecentPackage = package; } } return(mostRecentPackage); }
/// <summary> /// Parse "sdkmanager --list --verbose" output. /// NOTE: The --verbose output format is only reported by sdkmanager 26.0.2 and above. /// </summary> private AndroidSdkPackageCollection ParseListVerboseOutput( string sdkManagerListVerboseOutput) { var packages = new AndroidSdkPackageCollection(); // Whether we're parsing a set of packages. bool parsingPackages = false; // Whether we're parsing within the set of installed packages vs. available packages. bool parsingInstalledPackages = false; // Fields of the package being parsed. AndroidSdkPackage currentPackage = null; foreach (var rawLine in CommandLine.SplitLines(sdkManagerListVerboseOutput)) { var line = rawLine.Trim(); var lowerCaseLine = line.ToLower(); if (lowerCaseLine == AVAILABLE_UPDATES_HEADER) { parsingPackages = false; continue; } bool installedPackagesLine = lowerCaseLine == INSTALLED_PACKAGES_HEADER; bool availablePackagesLine = lowerCaseLine == AVAILABLE_PACKAGES_HEADER; if (installedPackagesLine || availablePackagesLine) { parsingPackages = true; parsingInstalledPackages = installedPackagesLine; continue; } else if (line.StartsWith("---")) { // Ignore section separators. continue; } else if (String.IsNullOrEmpty(line)) { if (currentPackage != null && !(String.IsNullOrEmpty(currentPackage.Name) || String.IsNullOrEmpty(currentPackage.VersionString))) { packages[currentPackage.Name].Add(currentPackage); } currentPackage = null; continue; } else if (!parsingPackages) { continue; } // Fields of the package are indented. bool indentedLine = rawLine.StartsWith(" "); if (!indentedLine) { // If this isn't an indented line it should be a package name. if (currentPackage == null) { currentPackage = new AndroidSdkPackage { Name = line, Installed = parsingInstalledPackages }; } } else if (currentPackage != null) { // Parse the package field. var fieldSeparatorIndex = line.IndexOf(":"); if (fieldSeparatorIndex >= 0) { var fieldName = line.Substring(0, fieldSeparatorIndex).Trim().ToLower(); var fieldValue = line.Substring(fieldSeparatorIndex + 1).Trim(); if (fieldName == "description") { currentPackage.Description = fieldValue; } else if (fieldName == "version") { currentPackage.VersionString = fieldValue; } } } } return(packages); }