diff --git a/.github/skills/update-androidsdk-packages/SKILL.md b/.github/skills/update-androidsdk-packages/SKILL.md index 3083692cb17..07891797b99 100644 --- a/.github/skills/update-androidsdk-packages/SKILL.md +++ b/.github/skills/update-androidsdk-packages/SKILL.md @@ -60,7 +60,7 @@ do not update it unattended; report the ambiguity instead. **5. Command-line tools are a coordinated product dependency.** Do not update only the bootstrap pins. A command-line-tools bump must also update `src/Xamarin.Installer.Build.Tasks/Xamarin.Installer.Common.props` and the matching latest entry in -`src/Xamarin.Installer.AndroidSDK/Feeds/AndroidManifestFeed_d18.0.xml`, including every published +`tools/workload-dependencies/AndroidManifestFeed_d18.0.xml`, including every published host/architecture archive. Confirm `CodeGenerator.targets` tracks the property file that supplies `AndroidCommandLineToolsVersion`. If the automated workflow is not authorized to change every required file, stop and report the coordinated update instead of opening a partial PR. diff --git a/.github/skills/update-androidsdk-packages/references/package-catalog.md b/.github/skills/update-androidsdk-packages/references/package-catalog.md index c0c5d624ada..445d9b86514 100644 --- a/.github/skills/update-androidsdk-packages/references/package-catalog.md +++ b/.github/skills/update-androidsdk-packages/references/package-catalog.md @@ -9,7 +9,7 @@ drift as the skill is used. |---|---|---|---|---| | build-tools | `build-tools` | `XABuildToolsVersion`, `XABuildToolsFolder` | `XABuildToolsHashMacOS/Linux/Windows` | `build-tools_r$(XABuildToolsVersion)_{macosx,linux,windows}.zip` | | platform-tools | `platform-tools` | `XAPlatformToolsVersion` | `XAPlatformToolsHashMacOS/Linux/Windows` | `platform-tools_r$(XAPlatformToolsVersion)-{darwin,linux,win}.zip` | -| cmdline-tools | `cmdline-tools` | `CommandLineToolsFolder`, `CommandLineToolsVersion`; shipped `AndroidCommandLineToolsVersion` in `src/Xamarin.Installer.Build.Tasks/Xamarin.Installer.Common.props` | `XACmdlineToolsHashMacOS`, `XACmdlineToolsHashMacOSArm64`, `XACmdlineToolsHashLinux/Windows` | `commandlinetools-{mac_x86_64,mac_arm64,linux,win}-$(CommandLineToolsVersion).zip`; also update the latest entry in `src/Xamarin.Installer.AndroidSDK/Feeds/AndroidManifestFeed_d18.0.xml` | +| cmdline-tools | `cmdline-tools` | `CommandLineToolsFolder`, `CommandLineToolsVersion`; shipped `AndroidCommandLineToolsVersion` in `src/Xamarin.Installer.Build.Tasks/Xamarin.Installer.Common.props` | `XACmdlineToolsHashMacOS`, `XACmdlineToolsHashMacOSArm64`, `XACmdlineToolsHashLinux/Windows` | `commandlinetools-{mac_x86_64,mac_arm64,linux,win}-$(CommandLineToolsVersion).zip`; also update the latest entry in `tools/workload-dependencies/AndroidManifestFeed_d18.0.xml` | | cmake | `cmake;` | `AndroidCmakeVersion` | `XACmakeHashMacOS/Linux/Windows` | `cmake-$(AndroidCmakeVersion)-{darwin,linux,windows}.zip` | | emulator | `emulator` | `EmulatorVersion`, `EmulatorPkgRevision` | `XAEmulatorHashMacOSx64`, `XAEmulatorHashMacOSArm64`, `XAEmulatorHashLinux/Windows` | `emulator-{darwin_x64,darwin_aarch64,linux_x64,windows_x64}-$(EmulatorVersion).zip`; also drives a synthesized `package.xml` via `package.xml.in` | | API 29 system image | `sys-img/android` manifest, `path="system-images;android-29;default;{x86_64,arm64-v8a}"` | (fixed `x86_64-29_r08*`/`arm64-v8a-29_r08` filenames — check manifest for a newer `rNN` if refreshing) | `XASystemImageHashMacOSx64/MacOSArm64/Linux/Windows` | `{x86_64,arm64-v8a}-29_r08{-darwin,-linux,-windows,}.zip` under `sys-img/android/` | diff --git a/Directory.Build.props b/Directory.Build.props index b4f653c3796..ce0c678b014 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -67,8 +67,6 @@ <_AllowProjectWarnings Condition=" '$(MSBuildProjectFile)' == 'NativeAOT.csproj' ">true <_AllowProjectWarnings Condition=" '$(MSBuildProjectFile)' == 'TestRunner.Core.NET.csproj' ">true <_AllowProjectWarnings Condition=" '$(MSBuildProjectFile)' == 'Xamarin.Android.JcwGen-Tests.csproj' ">true - <_AllowProjectWarnings Condition=" '$(MSBuildProjectFile)' == 'Xamarin.Installer.AndroidSDK.csproj' ">true - <_AllowProjectWarnings Condition=" '$(MSBuildProjectFile)' == 'Xamarin.Installer.Common.csproj' ">true true diff --git a/Documentation/docs-mobile/TOC.yml b/Documentation/docs-mobile/TOC.yml index 0a3c9377d2a..809177138e0 100644 --- a/Documentation/docs-mobile/TOC.yml +++ b/Documentation/docs-mobile/TOC.yml @@ -430,6 +430,12 @@ href: messages/xa5302.md - name: XA5305 href: messages/xa5305.md + - name: XA5306 + href: messages/xa5306.md + - name: XA5307 + href: messages/xa5307.md + - name: XA5308 + href: messages/xa5308.md - name: "XA6xxx: Internal tools" href: "messages/index.md#xa6xxx-internal-tools" - name: "XAccc7xxx: Unhandled MSBuild exceptions" diff --git a/Documentation/docs-mobile/building-apps/build-properties.md b/Documentation/docs-mobile/building-apps/build-properties.md index 0a4a5a68cd5..cf9a47047dd 100644 --- a/Documentation/docs-mobile/building-apps/build-properties.md +++ b/Documentation/docs-mobile/building-apps/build-properties.md @@ -944,33 +944,15 @@ If you want detailed output from the tool you can add the following to the ## AndroidManifestType -An enum-style property with valid values of `Xamarin` or `GoogleV2`. -This controls which repository is used by the -[`InstallAndroidDependencies`](build-targets.md#installandroiddependencies) -target to determine which Android packages and package versions are -available and can be installed. - -`Xamarin` is the **Approved List (Recommended)** repository within the -[Visual Studio SDK Manager](/xamarin/android/get-started/installation/android-sdk?tabs=windows#repository-selection). - -`GoogleV2` is the **Full List (Unsupported)** repository within the -[Visual Studio SDK Manager](/xamarin/android/get-started/installation/android-sdk?tabs=windows#repository-selection). - -If `$(AndroidManifestType)` is not set, then `Xamarin` is used. +This property was removed in .NET 12 and has no effect. +The [`InstallAndroidDependencies`](build-targets.md#installandroiddependencies) +target now uses the Android CLI to install Android SDK packages. ## AndroidManifestSource -A string property that specifies an absolute URI or an existing local file path -for the repository manifest used by the -[`InstallAndroidDependencies`](build-targets.md#installandroiddependencies) -target. When this property is not set, the default repository manifest selected -by `$(AndroidManifestType)` is used. - -For example: - -```xml -https://example.com/AndroidManifestFeed.xml -``` +This property was removed in .NET 12 and has no effect. +The [`InstallAndroidDependencies`](build-targets.md#installandroiddependencies) +target now uses the Android CLI to install Android SDK packages. ## AndroidManifestPlaceholders diff --git a/Documentation/docs-mobile/building-apps/build-targets.md b/Documentation/docs-mobile/building-apps/build-targets.md index 65dfdd5f59c..73fb4016e54 100644 --- a/Documentation/docs-mobile/building-apps/build-targets.md +++ b/Documentation/docs-mobile/building-apps/build-targets.md @@ -157,6 +157,19 @@ MSBuild /t:Install ProjectName.csproj /p:AdbTarget=-e Calls the [`GetAndroidDependencies`](#getandroiddependencies) target, then installs the Android SDK packages specified in the `@(AndroidDependency)` item group. +The Android SDK packages are installed with Google's +[Android CLI](https://developer.android.com/tools/agents/android-cli) +(`android sdk install`). The target downloads a pinned version of the Android CLI +from Google into a per-user cache. Before it runs the Android CLI, the target +makes sure that the SHA-256 hash of the file is the same as the hash included with +the .NET for Android SDK. The Android CLI is available for Windows x64, macOS (x64 +and Arm64), and Linux (x64 and Arm64). + +The Android CLI accepts the Android SDK licenses without a prompt. Thus, if Android SDK +packages must be installed, this target fails unless you set `$(AcceptAndroidSDKLicenses)` +to `true`. Before you set this +property, read the [Android SDK License Agreement](https://developer.android.com/studio/terms). + Before it extracts a downloaded Microsoft OpenJDK archive, this target verifies the archive's detached digital signature. The signing key must match the trusted key hash included with the .NET for Android SDK. Missing or invalid signatures @@ -173,13 +186,16 @@ you will get the following error: error MSB4057: The target "InstallAndroidDependencies" does not exist in the project. ``` -The `AndroidSdkDirectory` and `JavaSdkDirectory` properties are required as we need to know where to install the required components. These directories can be empty or existing. Sdk components -will be installed on top on an existing sdk installation. +The `AndroidSdkDirectory` and `JavaSdkDirectory` properties set where the components are installed. +These directories can be empty or existing. Sdk components will be installed on top of an existing sdk installation. +If a property is not set, the build looks for an existing installation, the same as a normal build. +If it finds no installation, `AndroidSdkDirectory` uses the `ANDROID_HOME` or `ANDROID_SDK_ROOT` environment variable. +If those are also not set, the default is `%LOCALAPPDATA%\Android\Sdk` on Windows, `~/Library/Android/sdk` on macOS, +and `~/Android/Sdk` on Linux. +`JavaSdkDirectory` uses the `JAVA_HOME` or `JDK_HOME` environment variable. +If those are also not set, the default is `%LOCALAPPDATA%\Android\jdk-` on Windows and +`~/Library/Android/microsoft-.jdk` on macOS. On Linux, you must set `JavaSdkDirectory` or `JAVA_HOME`. -The [`$(AndroidManifestType)`](build-properties.md#androidmanifesttype) -MSBuild property controls which -[Visual Studio SDK Manager repository](/xamarin/android/get-started/installation/android-sdk?tabs=windows#repository-selection) -is used for package name and package version detection, and URLs to download. ## Publish diff --git a/Documentation/docs-mobile/messages/index.md b/Documentation/docs-mobile/messages/index.md index 638566e1a6c..d8b547c2b79 100644 --- a/Documentation/docs-mobile/messages/index.md +++ b/Documentation/docs-mobile/messages/index.md @@ -282,6 +282,9 @@ Either change the value in the AndroidManifest.xml to match the $(SupportedOSPla + [XA5303](xa5303.md): Failed to parse 'DescriptorIndex' metadata value '{value}' for assembly '{assembly}'. + [XA5304](xa5304.md): Invalid AssemblyStore compression level '{level}'. The value must be between {min} and {max}. + [XA5305](xa5305.md): Could not verify the Microsoft OpenJDK archive signature. ++ [XA5306](xa5306.md): The Android CLI is not available for this operating system and architecture. ++ [XA5307](xa5307.md): The SHA-256 hash of the downloaded Android CLI is not correct. ++ [XA5308](xa5308.md): The Android CLI failed while it installed Android SDK packages. ## XA6xxx: Internal tools diff --git a/Documentation/docs-mobile/messages/xa5306.md b/Documentation/docs-mobile/messages/xa5306.md new file mode 100644 index 00000000000..73ceebcd148 --- /dev/null +++ b/Documentation/docs-mobile/messages/xa5306.md @@ -0,0 +1,30 @@ +--- +title: .NET for Android error XA5306 +description: XA5306 error code +ms.date: 11/12/2026 +f1_keywords: + - "XA5306" +--- + +# .NET for Android error XA5306 + +## Example messages + +```text +error XA5306: The Android CLI is not available for this operating system and architecture: `{os}` `{architecture}`. +``` + +## Issue + +`InstallAndroidDependencies` installs Android SDK packages with Google's +[Android CLI](https://developer.android.com/tools/agents/android-cli). Google +does not publish the Android CLI for the current operating system and processor +architecture. The Android CLI is available for Windows x64, macOS (x64 and +Arm64), and Linux (x64 and Arm64). + +## Solution + +Run `InstallAndroidDependencies` on a supported operating system and +architecture. Alternatively, install the Android SDK packages with Android +Studio or the Android SDK command-line tools, and set `$(AndroidSdkDirectory)` +to that Android SDK. diff --git a/Documentation/docs-mobile/messages/xa5307.md b/Documentation/docs-mobile/messages/xa5307.md new file mode 100644 index 00000000000..d8040fac891 --- /dev/null +++ b/Documentation/docs-mobile/messages/xa5307.md @@ -0,0 +1,30 @@ +--- +title: .NET for Android error XA5307 +description: XA5307 error code +ms.date: 11/12/2026 +f1_keywords: + - "XA5307" +--- + +# .NET for Android error XA5307 + +## Example messages + +```text +error XA5307: The Android CLI downloaded from `{url}` has SHA-256 `{actual}`, but SHA-256 `{expected}` was expected. The Android CLI will not be used. +``` + +## Issue + +`InstallAndroidDependencies` downloads a pinned version of Google's +[Android CLI](https://developer.android.com/tools/agents/android-cli). Before it +runs the Android CLI, it makes sure that the SHA-256 hash of the downloaded file +is the same as the hash included with the .NET for Android SDK. The hashes are +different, so the Android CLI is not used. A proxy that changes downloads, an +incomplete download, or a changed file on the server can cause this error. + +## Solution + +Check network access to the download URL, and try again. Use an up-to-date +.NET for Android SDK. If the error continues, report it with the URL and both +hashes. Do not use an Android CLI whose hash is not correct. diff --git a/Documentation/docs-mobile/messages/xa5308.md b/Documentation/docs-mobile/messages/xa5308.md new file mode 100644 index 00000000000..502f0dd61a0 --- /dev/null +++ b/Documentation/docs-mobile/messages/xa5308.md @@ -0,0 +1,29 @@ +--- +title: .NET for Android error XA5308 +description: XA5308 error code +ms.date: 11/12/2026 +f1_keywords: + - "XA5308" +--- + +# .NET for Android error XA5308 + +## Example messages + +```text +error XA5308: The Android CLI failed with exit code {code} while it installed Android SDK packages. Output: +{output} +``` + +## Issue + +`InstallAndroidDependencies` runs `android sdk install` from Google's +[Android CLI](https://developer.android.com/tools/agents/android-cli) to install +Android SDK packages. The Android CLI stopped with an error. The error message +includes the last part of the Android CLI output. + +## Solution + +Read the Android CLI output in the error message. Make sure that you can write +to `$(AndroidSdkDirectory)`, that you have network access, and that the disk has +sufficient free space. Then try again. diff --git a/Documentation/guides/InstallBuildsFromMain.md b/Documentation/guides/InstallBuildsFromMain.md index 05585c78550..d1753db7607 100644 --- a/Documentation/guides/InstallBuildsFromMain.md +++ b/Documentation/guides/InstallBuildsFromMain.md @@ -49,7 +49,7 @@ On Windows, if your Android SDK is located in `C:\Program Files administrator to run: ```dotnetcli -> dotnet build -t:InstallAndroidDependencies -p:AndroidManifestType=GoogleV2 -p:AcceptAndroidSDKLicenses=true +> dotnet build -t:InstallAndroidDependencies -p:AcceptAndroidSDKLicenses=true ``` *On macOS, you might not even need `sudo` for this command.* diff --git a/Microsoft.Android.slnx b/Microsoft.Android.slnx index 7764be2f0a6..e1a23adbce9 100644 --- a/Microsoft.Android.slnx +++ b/Microsoft.Android.slnx @@ -44,9 +44,7 @@ - - diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index 2f3c4fa0890..8c62ac6e89a 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -136,19 +136,13 @@ - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ICSharpCode.SharpZipLib.dll" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ICSharpCode.SharpZipLib.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Build.Debugging.Tasks.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Build.Debugging.Tasks.pdb" /> <_MSBuildFiles Include="@(_LocalizationLanguages->'$(MicrosoftAndroidSdkOutDir)%(Identity)\Xamarin.Android.Build.Debugging.Tasks.resources.dll')" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Common.Debugging.props" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Common.Debugging.targets" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Installer.AndroidSDK.dll" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Installer.AndroidSDK.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Installer.Build.Tasks.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Installer.Build.Tasks.pdb" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Installer.Common.dll" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Installer.Common.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Installer.Common.props" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Installer.Common.targets" /> diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs index 7dc2ff30d89..f9411fa933d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs @@ -2,7 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Security.Cryptography; +using System.Net; +using System.Net.Http; using System.Text; using System.Threading; using System.Xml.Linq; @@ -10,13 +11,10 @@ using Microsoft.Android.Build.Tasks; using Xamarin.Android.Tasks; using Xamarin.Android.Tools; -using Xamarin.Installer.AndroidSDK; -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.AndroidSDK.Manager; -using Xamarin.Installer.Common; using Xamarin.ProjectTools; using Microsoft.Build.Framework; -using System.IO.Compression; +using Microsoft.Build.Utilities; +using Xamarin.Installer.Build.Tasks; namespace Xamarin.Android.Build.Tests { @@ -26,30 +24,16 @@ public class AndroidDependenciesTests : BaseTest { [Test] [NonParallelizable] // Do not run environment modifying tests in parallel. - public void InstallAndroidDependenciesTest ([Values ("GoogleV2", "Xamarin")] string manifestType, [Values (AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] AndroidRuntime runtime) + public void InstallAndroidDependenciesTest ([Values (AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] AndroidRuntime runtime) { bool isRelease = runtime == AndroidRuntime.NativeAOT; if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { return; } - // The GoogleV2 manifest from Google doesn't have an ndk-bundle component, - // so the NDK dependency can't be resolved for runtimes that require it. - if (manifestType == "GoogleV2" && runtime == AndroidRuntime.NativeAOT) { - Assert.Ignore ("GoogleV2 manifest does not have an ndk-bundle component for NativeAOT"); - } - if (manifestType == "GoogleV2") { - InstallGoogleV2Dependencies (); - return; - } - - // Set to true when we are marking a new Android API level as stable, but it has not - // been added to the Xamarin manifest yet. - var xamarin_manifest_needs_updating = false; - var oldSdkPath = Environment.GetEnvironmentVariable ("TEST_ANDROID_SDK_PATH"); var oldJdkPath = Environment.GetEnvironmentVariable ("TEST_ANDROID_JDK_PATH"); - var outdatedCommandLineToolsRevision = new Version (19, 0); + try { string sdkPath = Path.Combine (Root, "temp", TestName, "android-sdk"); string jdkPath = Path.Combine (Root, "temp", TestName, "android-jdk"); @@ -62,13 +46,10 @@ public void InstallAndroidDependenciesTest ([Values ("GoogleV2", "Xamarin")] str proj.SetRuntime (runtime); var buildArgs = new List { "AcceptAndroidSDKLicenses=true", - $"AndroidManifestType={manifestType}", + // This integration test downloads the SDK, JDK and (for NativeAOT) NDK from scratch. "AndroidDependencyInstallationTimeout=30", }; - var manifestPath = Path.Combine (XABuildPaths.TopDirectory, "src", "Xamarin.Installer.AndroidSDK", "Feeds", "AndroidManifestFeed_d18.0.xml"); - Assert.IsTrue (File.Exists (manifestPath), $"Xamarin manifest does not exist at '{manifestPath}'."); - buildArgs.Add ($"AndroidManifestSource={manifestPath}"); using (var b = CreateApkBuilder ()) { b.Verbosity = LoggerVerbosity.Detailed; @@ -103,9 +84,6 @@ public void InstallAndroidDependenciesTest ([Values ("GoogleV2", "Xamarin")] str Directory.CreateDirectory (path); } - var commandLineToolsPath = Path.Combine (sdkPath, "cmdline-tools", "latest"); - Directory.CreateDirectory (commandLineToolsPath); - File.WriteAllText (Path.Combine (commandLineToolsPath, "source.properties"), $"Pkg.Revision={outdatedCommandLineToolsRevision}"); if (b.Build (proj, parameters: buildArgs.ToArray ())) { installSucceeded = true; @@ -118,30 +96,12 @@ public void InstallAndroidDependenciesTest ([Values ("GoogleV2", "Xamarin")] str } Assert.IsTrue (installSucceeded, $"InstallAndroidDependencies should have succeeded within {maxInstallAttempts} attempts."); - var sourceProperties = Path.Combine (sdkPath, "cmdline-tools", "latest", "source.properties"); - var revisionProperty = File.ReadLines (sourceProperties) - .First (line => line.StartsWith ("Pkg.Revision", StringComparison.Ordinal)); - int separator = revisionProperty.IndexOf ('='); - Assert.GreaterOrEqual (separator, 0, "The command-line tools revision property should contain a value."); - var installedRevision = Version.Parse (revisionProperty.Substring (separator + 1).Trim ()); - Assert.Greater (installedRevision.CompareTo (outdatedCommandLineToolsRevision), 0, "The outdated command-line tools installation should have been updated."); - - // When dependencies can not be resolved/installed a warning will be present in build output: - // Dependency `platform-tools` should have been installed but could not be resolved. - var depFailedMessage = "should have been installed but could not be resolved"; - bool failedToInstall = b.LastBuildOutput.ContainsText (depFailedMessage); - - // If we don't think the Xamarin manifest has been updated to contain the new API level: - // - Don't error if we got the expected failure - // - Error if didn't get a failure, because we need to update this test - if (manifestType == "Xamarin" && xamarin_manifest_needs_updating) { - if (!failedToInstall) - Assert.Fail ("We didn't expect the Xamarin manifest to have the requested component. If the manifest has been updated, change 'InstallAndroidDependenciesTest.xamarin_manifest_needs_updating' to be 'false'. "); + FileAssert.Exists (Path.Combine (sdkPath, "cmdline-tools", "21.0", "source.properties")); - return; - } - - if (failedToInstall) { + // When a package is not installed, a warning is present in the build output: + // The Android CLI did not install Android SDK package `platform-tools` into `...`. + var depFailedMessage = "The Android CLI did not install Android SDK package"; + if (b.LastBuildOutput.ContainsText (depFailedMessage)) { var sb = new StringBuilder (); foreach (var line in b.LastBuildOutput) { if (line.Contains (depFailedMessage)) { @@ -167,321 +127,6 @@ public void InstallAndroidDependenciesTest ([Values ("GoogleV2", "Xamarin")] str } } - void InstallGoogleV2Dependencies () - { - string sdkPath = Path.Combine (Root, "temp", TestName, "android-sdk"); - if (Directory.Exists (sdkPath)) - Directory.Delete (sdkPath, recursive: true); - Directory.CreateDirectory (sdkPath); - - var fixture = new GoogleV2Fixture (); - string platformToolsVersion = GetCurrentPlatformToolsVersion (fixture.RepositoryManifest); - var installer = new AndroidSDKInstaller ( - fixture.Helpers, - AndroidManifestType.GoogleV2, - fixture.ManifestUrl, - fixture.AddonsListUrl, - fixture.RepositoryBaseUrl); - installer.Discover (new List { sdkPath }); - - var sdk = installer.FindInstance (sdkPath); - Assert.IsNotNull (sdk, $"The synthetic Android SDK should be discovered at '{sdkPath}'."); - - var requested = new [] { - (path: $"platforms;android-{GoogleV2Fixture.PlatformVersion}", version: (string) null), - (path: $"build-tools;{GoogleV2Fixture.BuildToolsVersion}", version: GoogleV2Fixture.BuildToolsVersion), - (path: "platform-tools", version: platformToolsVersion), - (path: $"cmdline-tools;{GoogleV2Fixture.CommandLineToolsVersion}", version: GoogleV2Fixture.CommandLineToolsVersion), - }; - var components = new List (); - foreach (var dependency in requested) { - var version = dependency.version == null ? null : new AndroidRevision (dependency.version); - var component = sdk.Components.FirstOrDefault (c => c.Path == dependency.path && (version == null || c.Revision == version)); - Assert.IsNotNull (component, $"The synthetic repository should contain '{dependency.path}/{dependency.version}'."); - components.Add (component); - } - - var installationSet = installer.GetInstallationSet (sdk, components); - CollectionAssert.AreEquivalent ( - requested.Select (dependency => dependency.path).Append (GoogleV2Fixture.FixtureDependencyPath), - installationSet.Select (component => component.Path), - "The installation set should contain direct and transitive GoogleV2 dependencies."); - - var downloads = installer.GetDownloadItems (installationSet); - fixture.PrepareDownloads (downloads, Path.Combine (Root, "temp", TestName, "downloads")); - foreach (var download in downloads) - Assert.IsTrue (download.IsDownloadValid (), $"Checksum validation should succeed for '{download.Url}'."); - - var licenses = installationSet - .Select (component => component.License) - .Where (license => license != null) - .Distinct () - .ToList (); - Assert.AreEqual (1, licenses.Count, "The synthetic GoogleV2 license should be parsed."); - Assert.AreEqual ("android-sdk-license", licenses [0].ID); - installer.Install (sdk, installationSet); - - string javaSdkPath = AndroidSdkResolver.GetJavaSdkPath (); - Assert.IsTrue (Directory.Exists (javaSdkPath), $"The configured local JDK should exist at '{javaSdkPath}'."); - installer.AcceptLicensesAsync (sdk, licenses, CancellationToken.None, javaSdkPath, throwsErrorIfValidationFailed: true) - .GetAwaiter ().GetResult (); - Assert.IsTrue (File.Exists (Path.Combine (sdkPath, "cmdline-tools", GoogleV2Fixture.CommandLineToolsVersion, "bin", "sdkmanager-invoked.txt")), - "The synthetic sdkmanager should be invoked to accept licenses."); - Assert.IsTrue (installer.IsLicenseAccepted (sdk, licenses [0]), "The synthetic GoogleV2 license should be accepted."); - fixture.AssertInstallation (sdkPath); - } - - static string GetCurrentPlatformToolsVersion (XDocument manifest) - { - var platformToolsPackage = manifest.Root.Elements ("remotePackage") - .Where (e => "platform-tools" == (string) e.Attribute("path") && - "android-sdk-preview-license" != (string) e.Element ("uses-license")?.Attribute ("ref")) - .FirstOrDefault (); - Assert.IsNotNull (platformToolsPackage, "The GoogleV2 manifest should contain a stable platform-tools package."); - - var revision = platformToolsPackage.Element ("revision"); - Assert.IsNotNull (revision, "The stable platform-tools package should contain a revision."); - - return $"{revision.Element ("major")?.Value}.{revision.Element ("minor")?.Value}.{revision.Element ("micro")?.Value}"; - } - - sealed class GoogleV2Fixture - { - public const string PlatformToolsVersion = "99.0.1"; - public const string BuildToolsVersion = "37.0.0"; - public const string CommandLineToolsVersion = "22.0"; - public const string PlatformVersion = "37.0"; - public const string FixtureDependencyPath = "extras;googlev2-fixture"; - - readonly Dictionary archives = new Dictionary (); - readonly List requests = new List (); - readonly List expectedRequests = new List { - "/repository2-3.xml", - "/addons_list-5.xml", - "/addon.xml", - "/platform-tools.zip", - "/build-tools.zip", - "/command-line-tools.zip", - "/platform.zip", - "/fixture-dependency.zip", - }; - - public FixtureHelpers Helpers { get; } - public Uri RepositoryBaseUrl { get; } = new Uri ("https://googlev2-fixture.test/"); - public Uri ManifestUrl => new Uri (RepositoryBaseUrl, "repository2-3.xml"); - public Uri AddonsListUrl => new Uri (RepositoryBaseUrl, "addons_list-5.xml"); - public XDocument RepositoryManifest { get; } - - public GoogleV2Fixture () - { - Helpers = new FixtureHelpers (requests); - var platformToolsArchive = CreateArchive ( - ("platform-tools/source.properties", $"Pkg.Revision={PlatformToolsVersion}"), - ("platform-tools/fixture-marker.txt", "synthetic platform-tools")); - var buildToolsArchive = CreateArchive ( - ($"android-{BuildToolsVersion}/source.properties", $"Pkg.Revision={BuildToolsVersion}"), - ($"android-{BuildToolsVersion}/fixture-marker.txt", "synthetic build-tools")); - var platformArchive = CreateArchive ( - ($"android-{PlatformVersion}/source.properties", "Pkg.Revision=1"), - ($"android-{PlatformVersion}/android.jar", "synthetic android.jar")); - var fixtureDependencyArchive = CreateArchive ( - ("googlev2-fixture/source.properties", "Pkg.Revision=1"), - ("googlev2-fixture/nested/fixture-marker.txt", "synthetic transitive dependency")); - var sdkManagerName = TestEnvironment.IsWindows ? "sdkmanager.bat" : "sdkmanager"; - var sdkManagerContents = TestEnvironment.IsWindows - ? "@echo off\r\necho invoked>sdkmanager-invoked.txt\r\necho Accepted\r\nexit /b 0\r\n" - : "#!/bin/sh\necho invoked > sdkmanager-invoked.txt\necho Accepted\nexit 0\n"; - var commandLineToolsArchive = CreateCommandLineToolsArchive ( - ("cmdline-tools/source.properties", $"Pkg.Revision={CommandLineToolsVersion}"), - ($"cmdline-tools/bin/{sdkManagerName}", sdkManagerContents)); - - AddArchive ("platform-tools.zip", platformToolsArchive); - AddArchive ("build-tools.zip", buildToolsArchive); - AddArchive ("platform.zip", platformArchive); - AddArchive ("fixture-dependency.zip", fixtureDependencyArchive); - AddArchive ("command-line-tools.zip", commandLineToolsArchive); - RepositoryManifest = CreateRepositoryManifest ( - platformToolsArchive, - buildToolsArchive, - platformArchive, - fixtureDependencyArchive, - commandLineToolsArchive); - Helpers.AddResponse (ManifestUrl, RepositoryManifest.ToString (SaveOptions.DisableFormatting)); - Helpers.AddResponse (AddonsListUrl, CreateAddonsListManifest ()); - Helpers.AddResponse (new Uri (RepositoryBaseUrl, "addon.xml"), ""); - } - - public void PrepareDownloads (IEnumerable downloads, string directory) - { - if (Directory.Exists (directory)) - Directory.Delete (directory, recursive: true); - Directory.CreateDirectory (directory); - - foreach (var download in downloads) { - requests.Add (download.Url.AbsolutePath); - Assert.IsTrue (archives.TryGetValue (download.Url, out byte [] contents), - $"Unexpected GoogleV2 fixture archive '{download.Url}'."); - string path = Path.Combine (directory, Path.GetFileName (download.Url.LocalPath)); - File.WriteAllBytes (path, contents); - download.DownloadedFilePath = path; - } - } - - public void AssertInstallation (string sdkPath) - { - AssertFixtureFile (sdkPath, "platform-tools", "fixture-marker.txt"); - AssertFixtureFile (sdkPath, "build-tools", BuildToolsVersion, "fixture-marker.txt"); - AssertFixtureFile (sdkPath, "cmdline-tools", CommandLineToolsVersion, "source.properties"); - AssertFixtureFile (sdkPath, "platforms", $"android-{PlatformVersion}", "android.jar"); - AssertFixtureFile (sdkPath, "extras", "googlev2-fixture", "nested", "fixture-marker.txt"); - - CollectionAssert.AreEquivalent (expectedRequests, requests, - "GoogleV2 should only access the expected in-memory fixture resources."); - } - - void AddArchive (string name, byte [] contents) - { - archives.Add (new Uri (RepositoryBaseUrl, name), contents); - } - - static void AssertFixtureFile (string sdkPath, params string [] parts) - { - var path = parts.Aggregate (sdkPath, Path.Combine); - Assert.IsTrue (File.Exists (path), $"Expected synthetic GoogleV2 fixture file '{path}' to be installed."); - Assert.IsTrue (File.Exists (Path.Combine (Path.GetDirectoryName (path), "package.xml")) || - File.Exists (Path.Combine (Path.GetDirectoryName (Path.GetDirectoryName (path)), "package.xml")), - $"Expected a package.xml next to the installed GoogleV2 fixture '{path}'."); - } - - XDocument CreateRepositoryManifest ( - byte [] platformToolsArchive, - byte [] buildToolsArchive, - byte [] platformArchive, - byte [] fixtureDependencyArchive, - byte [] commandLineToolsArchive) - { - XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance"; - return new XDocument ( - new XElement ("repository", - new XAttribute (XNamespace.Xmlns + "xsi", xsi), - new XElement ("license", new XAttribute ("id", "android-sdk-license"), "Synthetic test license"), - new XElement ("channel", new XAttribute ("id", "channel-0"), "stable"), - CreatePackage ("platform-tools", PlatformToolsVersion, "platform-tools.zip", platformToolsArchive), - CreatePackage ($"build-tools;{BuildToolsVersion}", BuildToolsVersion, "build-tools.zip", buildToolsArchive), - CreatePackage ($"cmdline-tools;{CommandLineToolsVersion}", CommandLineToolsVersion, "command-line-tools.zip", commandLineToolsArchive), - CreatePackage ( - $"platforms;android-{PlatformVersion}", - "1.0.0", - "platform.zip", - platformArchive, - new XElement ("dependencies", - new XElement ("dependency", - new XAttribute ("path", FixtureDependencyPath)))), - CreatePackage (FixtureDependencyPath, "1.0.0", "fixture-dependency.zip", fixtureDependencyArchive) - ) - ); - } - - XElement CreatePackage (string path, string version, string archiveName, byte [] archive, XElement dependencies = null) - { - XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance"; - return new XElement ("remotePackage", - new XAttribute ("path", path), - new XElement ("type-details", new XAttribute (xsi + "type", "genericDetailsType")), - CreateRevision (version), - new XElement ("display-name", $"Synthetic {path}"), - new XElement ("uses-license", new XAttribute ("ref", "android-sdk-license")), - new XElement ("channelRef", new XAttribute ("ref", "channel-0")), - dependencies, - new XElement ("archives", - new XElement ("archive", - new XElement ("complete", - new XElement ("size", archive.Length), - new XElement ("checksum", new XAttribute ("type", "sha256"), Files.ToHexString (SHA256.HashData (archive)).ToLowerInvariant ()), - new XElement ("url", new Uri (RepositoryBaseUrl, archiveName)))))); - } - - static XElement CreateRevision (string version) - { - var fields = version.Split ('.').Select (int.Parse).ToArray (); - return new XElement ("revision", - new XElement ("major", fields [0]), - fields.Length > 1 ? new XElement ("minor", fields [1]) : null, - fields.Length > 2 ? new XElement ("micro", fields [2]) : null); - } - - string CreateAddonsListManifest () - { - XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance"; - return new XDocument ( - new XElement ("sdk-addons-list", - new XAttribute (XNamespace.Xmlns + "xsi", xsi), - new XAttribute (XNamespace.Xmlns + "sdk", "http://schemas.android.com/sdk/android/repo/addons-list/3"), - new XElement ("site", - new XAttribute (xsi + "type", "sdk:addonSiteType"), - new XElement ("displayName", "Synthetic add-on repository"), - new XElement ("url", new Uri (RepositoryBaseUrl, "addon.xml")))) - ).ToString (SaveOptions.DisableFormatting); - } - - static byte [] CreateArchive (params (string path, string contents) [] entries) - { - using (var stream = new MemoryStream ()) { - using (var archive = new ZipArchive (stream, ZipArchiveMode.Create, leaveOpen: true)) { - foreach (var entry in entries) { - using var writer = new StreamWriter (archive.CreateEntry (entry.path).Open (), new UTF8Encoding (false)); - writer.Write (entry.contents); - } - } - return stream.ToArray (); - } - } - - static byte [] CreateCommandLineToolsArchive ( - (string path, string contents) sourceProperties, - (string path, string contents) sdkManager) - { - using (var stream = new MemoryStream ()) { - using (var archive = new ZipArchive (stream, ZipArchiveMode.Create, leaveOpen: true)) { - using (var writer = new StreamWriter (archive.CreateEntry (sourceProperties.path).Open (), new UTF8Encoding (false))) - writer.Write (sourceProperties.contents); - var entry = archive.CreateEntry (sdkManager.path); - entry.ExternalAttributes = ((int)(UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute | - UnixFileMode.GroupRead | UnixFileMode.GroupExecute | - UnixFileMode.OtherRead | UnixFileMode.OtherExecute) | 0x8000) << 16; - using var scriptWriter = new StreamWriter (entry.Open (), new UTF8Encoding (false)); - scriptWriter.Write (sdkManager.contents); - } - return stream.ToArray (); - } - } - - } - - sealed class FixtureHelpers : Helper, IHelpers - { - readonly Dictionary responses = new Dictionary (); - readonly List requests; - - public FixtureHelpers (List requests) - { - this.requests = requests; - } - - public void AddResponse (Uri uri, string contents) - { - responses.Add (uri, contents); - } - - bool IHelpers.DownloadToString (Uri url, out string output) - { - requests.Add (url.AbsolutePath); - if (!responses.TryGetValue (url, out output)) - throw new InvalidOperationException ($"Unexpected GoogleV2 fixture manifest '{url}'."); - return true; - } - } - [TestCase (AndroidRuntime.CoreCLR, false, false, false)] [TestCase (AndroidRuntime.CoreCLR, false, true, true)] [TestCase (AndroidRuntime.NativeAOT, true, false, true)] @@ -604,6 +249,65 @@ public void GetDependencyWhenSDKIsMissingTest ([Values] bool createSdkDirectory, } } + [Test] + public void InstallAndroidDependenciesPassesPackagesToAndroidCli () + { + var root = Path.Combine (Root, "temp", TestName); + if (Directory.Exists (root)) + Directory.Delete (root, recursive: true); + Directory.CreateDirectory (root); + + // A fake Android CLI that writes its arguments to args.txt. + string cli; + if (OperatingSystem.IsWindows ()) { + cli = Path.Combine (root, "android.cmd"); + File.WriteAllText (cli, "@echo %* > \"%~dp0args.txt\"\r\n"); + } else { + cli = Path.Combine (root, "android"); + File.WriteAllText (cli, "#!/bin/sh\necho \"$@\" > \"$(dirname \"$0\")/args.txt\"\n"); + File.SetUnixFileMode (cli, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute); + } + + var errors = new List (); + var task = new InstallAndroidDependencies { + BuildEngine = new MockBuildEngine (TestContext.Out, errors, [], []), + AndroidSdkPath = Path.Combine (root, "sdk"), + AcceptAndroidSDKLicenses = true, + InstallJavaDependencies = false, + AndroidCliPath = cli, + JavaDependencies = [], + Dependencies = [ + new TaskItem ("build-tools/37.0.0", new Dictionary { { "Version", "37.0.0" } }), + new TaskItem ("platform-tools", new Dictionary { { "Version", "37.0.1" } }), + new TaskItem ("ndk-bundle", new Dictionary { { "Version", "27.2.12479018" } }), + new TaskItem ("platforms/android-37.0"), + ], + }; + Assert.IsTrue (task.Execute (), string.Join (Environment.NewLine, errors.Select (e => e.Message))); + + var args = File.ReadAllText (Path.Combine (root, "args.txt")).Trim (); + StringAssert.Contains ($"--no-metrics --sdk={Path.Combine (root, "sdk")} sdk install", args); + StringAssert.EndsWith ("build-tools/37.0.0 platform-tools@37.0.1 ndk/27.2.12479018 platforms/android-37.0", args); + } + + [Test] + public async System.Threading.Tasks.Task UnknownJdkVersionIsNotValid () + { + // aka.ms sends an unknown link to an HTML page on bing.com with status 200. + using (var client = new HttpClient (new HtmlHandler ())) { + var archive = await new JavaDependencyInstaller ().GetFirstValidJdkArchiveWithVersion (client, "21.0.99", CancellationToken.None); + Assert.IsNull (archive); + } + } + + sealed class HtmlHandler : HttpMessageHandler + { + protected override System.Threading.Tasks.Task SendAsync (HttpRequestMessage request, CancellationToken cancellationToken) => + System.Threading.Tasks.Task.FromResult (new HttpResponseMessage (HttpStatusCode.OK) { + Content = new StringContent ("", Encoding.UTF8, "text/html"), + }); + } + static readonly XNamespace MSBuildXmlns = "http://schemas.microsoft.com/developer/msbuild/2003"; static string GetExpectedBuildToolsVersion () diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/OpenJdkSignatureTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/OpenJdkSignatureTests.cs index c7c52f40d39..21d67b8c1b4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/OpenJdkSignatureTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/OpenJdkSignatureTests.cs @@ -12,7 +12,6 @@ using System.Xml.Linq; using Microsoft.Build.Framework; using NUnit.Framework; -using Xamarin.Installer.AndroidSDK.Common; using Xamarin.Installer.Build.Tasks; using Xamarin.ProjectTools; @@ -200,7 +199,7 @@ public void CancelledVerification (bool skip) Assert.Throws (() => Verify (archiveBytes, Sign (), cancellationToken: new CancellationToken (true))); using (var client = new HttpClient (new SignatureHandler ([], []))) { var task = new InstallAndroidDependencies { SkipSignCheck = skip }; - Assert.ThrowsAsync (async () => await task.VerifyJavaArchiveAsync (client, new Archive ("windows"), new CancellationToken (true))); + Assert.ThrowsAsync (async () => await task.VerifyJavaArchiveAsync (client, new Archive (), new CancellationToken (true))); } } @@ -223,7 +222,7 @@ public void HttpTimeoutReportsVerificationError (bool keyRequest) var task = new VerificationTask { BuildEngine = engine, Client = client, - Archive = new Archive ("windows") { Url = new Uri ("https://example.test/jdk.zip") }, + Archive = new Archive () { Url = new Uri ("https://example.test/jdk.zip") }, }; Assert.IsFalse (task.Execute ()); Assert.IsTrue (handler.Blocked); @@ -243,7 +242,7 @@ public void CallerCancellationDuringVerificationPropagates (bool keyRequest) using (var client = new HttpClient (handler) { Timeout = Timeout.InfiniteTimeSpan }) { var engine = CreateBuildEngine (); var task = new InstallAndroidDependencies { BuildEngine = engine }; - var archive = new Archive ("windows") { Url = new Uri ("https://example.test/jdk.zip") }; + var archive = new Archive () { Url = new Uri ("https://example.test/jdk.zip") }; Assert.CatchAsync (async () => await task.VerifyJavaArchiveAsync (client, archive, source.Token)); Assert.IsTrue (handler.Blocked); Assert.IsTrue (source.IsCancellationRequested); @@ -465,7 +464,7 @@ public void BypassDefaultsToFalseAndTargetForwardsPrivateProperty () public async Task PublishedMicrosoftArchive () { using (var client = new HttpClient { Timeout = TimeSpan.FromMinutes (10) }) { - var archive = new Archive ("windows") { + var archive = new Archive () { Url = new Uri ("https://aka.ms/download-jdk/microsoft-jdk-21.0.8-windows-x64.zip"), DownloadedFilePath = Path.GetTempFileName (), }; @@ -547,7 +546,7 @@ static bool RunVerificationTask (SignatureHandler handler, MockBuildEngine engin var task = new VerificationTask { BuildEngine = engine, Client = client, - Archive = new Archive ("windows") { + Archive = new Archive () { Url = new Uri ("https://example.test/jdk.tar.gz?token=test"), DownloadedFilePath = path, }, diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj index ba0219e2184..4bbfedfb8a6 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj @@ -24,7 +24,6 @@ - diff --git a/src/Xamarin.Installer.AndroidSDK/CodeGenerator.targets b/src/Xamarin.Installer.AndroidSDK/CodeGenerator.targets deleted file mode 100644 index 9bd54768669..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/CodeGenerator.targets +++ /dev/null @@ -1,37 +0,0 @@ - - - - $(MSBuildThisFileDirectory)..\Xamarin.Installer.Build.Tasks\Xamarin.Installer.Common.props - - - - - $(IntermediateOutputPath)RequiredComponentVersions.cs - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/AssemblyInfo.cs b/src/Xamarin.Installer.AndroidSDK/Properties/AssemblyInfo.cs deleted file mode 100644 index 7222449168a..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Xamarin Android SDK Installer")] -[assembly: AssemblyDescription("Xamarin Android SDK Installer")] -[assembly: AssemblyProduct("Xamarin Android SDK Manager")] -[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.Designer.cs b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.Designer.cs deleted file mode 100644 index c6dfd39f781..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.Designer.cs +++ /dev/null @@ -1,126 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Xamarin.Installer.AndroidSDK.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xamarin.Installer.AndroidSDK.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Accept Android licenses failed: Android SDK not found. - /// - internal static string AccepLicensesFailedAndroidSDKNotFound { - get { - return ResourceManager.GetString("AccepLicensesFailedAndroidSDKNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accept Android licenses failed: cmdline-tools not found. - /// - internal static string AccepLicensesFailedCMDLineToolsNotFound { - get { - return ResourceManager.GetString("AccepLicensesFailedCMDLineToolsNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Accept Android licenses failed: Java SDK not found. - /// - internal static string AccepLicensesFailedJavaSDKNotFound { - get { - return ResourceManager.GetString("AccepLicensesFailedJavaSDKNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Component installation failed. - /// - internal static string ComponentInstallationFailed { - get { - return ResourceManager.GetString("ComponentInstallationFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failure to load component properties file. - /// - internal static string FailedToLoadSourceProperties { - get { - return ResourceManager.GetString("FailedToLoadSourceProperties", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An error occurred trying to accept Android licenses. - /// - internal static string GoogleAccepLicensesFailed { - get { - return ResourceManager.GetString("GoogleAccepLicensesFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No suitable component archive found.. - /// - internal static string NoSuitableArchiveFound { - get { - return ResourceManager.GetString("NoSuitableArchiveFound", resourceCulture); - } - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.cs.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.cs.resx deleted file mode 100644 index b01eed2459a..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.cs.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Instalace komponenty se nezdařila. - - - Nepovedlo se načíst soubor vlastností komponenty. - - - Nenašel se žádný vhodný archiv komponent. - - - Při pokusu o přijetí licencí pro Android došlo k chybě. - - - Nepovedlo se přijmout licence na Android: nenalezena sada Android SDK - - - Nepovedlo se přijmout licence na Android: nenalezena sada Java SDK - - - Nepovedlo se přijmout licence pro Android: nenalezeny nástroje příkazového řádku - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.de.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.de.resx deleted file mode 100644 index 4c3daa050aa..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.de.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Fehler beim Installieren der Komponente. - - - Fehler beim Laden der Datei mit den Komponenteneigenschaften. - - - Es wurde kein geeignetes Komponentenarchiv gefunden. - - - Fehler beim Akzeptieren von Android-Lizenzen - - - Fehler beim Akzeptieren von Android-Lizenzen: Android SDK nicht gefunden - - - Fehler beim Akzeptieren von Android-Lizenzen: Java SDK nicht gefunden - - - Fehler beim Akzeptieren von Android-Lizenzen: cmdline-Tools nicht gefunden - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.es.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.es.resx deleted file mode 100644 index cbd83a51b89..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.es.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Fallo en la instalación de componentes - - - Error al cargar el archivo de propiedades del componente - - - No se encontró ningún archivo de componentes adecuado. - - - Error al intentar aceptar licencias de Android - - - Error al aceptar licencias de Android: no se encontró el SDK de Android - - - Error al aceptar licencias de Android: no se encontró el SDK de Java - - - Error al aceptar licencias de Android: cmdline-tools no encontrado - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.fr.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.fr.resx deleted file mode 100644 index 58ab878a959..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.fr.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Échec de l'installation du composant. - - - Échec du chargement du fichier des propriétés du composant - - - Aucune archive de composant appropriée n’a été trouvée. - - - Désolé, une erreur s’est produite lors de la tentative d’acceptation des licences Android. - - - Échec de l’acceptation des licences Android : Android SDK introuvable - - - Échec de l’acceptation des licences Android : SDK Java introuvable - - - Échec de l’acceptation des licences Android : outils de ligne de commande introuvables - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.it.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.it.resx deleted file mode 100644 index 455c9a46ba6..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.it.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - L'installazione del componente non è riuscita - - - Si è verificato un errore durante il caricamento del file delle proprietà del componente - - - Non sono stati trovati archivi di componenti appropriati. - - - Si è verificato un errore durante il tentativo di accettare le licenze di Android - - - L'accettazione delle licenze Android non è riuscita: Android SDK non trovato - - - L'accettazione delle licenze Android non è riuscita: Java SDK non trovato - - - Accettazione delle licenze Android non riuscita: cmdline-tools non trovato - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ja.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ja.resx deleted file mode 100644 index 15ff2df1c16..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ja.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - コンポーネントをインストールできませんでした。 - - - コンポーネント プロパティ ファイルの読み込みに失敗しました - - - 適切なコンポーネント アーカイブが見つかりませんでした。 - - - Android ライセンスを承諾しようとしてエラーが発生しました。 - - - Android ライセンスの承諾に失敗しました: Android SDK が見つかりません - - - Android ライセンスの承諾に失敗しました: Java SDK が見つかりません - - - Android ライセンスの承諾に失敗しました: cmdline-tools が見つかりません - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ko.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ko.resx deleted file mode 100644 index d6f2995c361..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ko.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 구성 요소 설치 실패 - - - 구성 요소 속성 파일 로드 실패 - - - 적절한 구성 요소 보관함을 찾을 수 없습니다. - - - Android 라이선스를 수락하는 동안 오류 발생 - - - Android 라이선스 수락 실패: Android SDK를 찾을 수 없음 - - - Android 라이선스 수락 실패: Java SDK를 찾을 수 없음 - - - Android 라이선스 수락 실패: cmdline-tools를 찾을 수 없음 - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.pl.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.pl.resx deleted file mode 100644 index 89745f6389e..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.pl.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Instalacja składników nie powiodła się - - - Nie można załadować pliku właściwości składników - - - Nie znaleziono odpowiedniego archiwum składników. - - - Wystąpił błąd podczas próby zaakceptowania licencji dla systemu Android - - - Zaakceptuj licencje dla systemu Android nie powiodło się: nie znaleziono zestawu Android SDK dla języka Java - - - Zaakceptuj licencje dla systemu Android nie powiodło się: nie znaleziono zestawu SDK dla języka Java - - - Zaakceptuj licencje dla systemu Android nie powiodło się: nie znaleziono narzędzi cmdline - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.pt-BR.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.pt-BR.resx deleted file mode 100644 index ec57b754bc4..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.pt-BR.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - A instalação do componente falhou - - - Falha ao carregar o arquivo de propriedades do componente - - - Nenhum arquivo de componente adequado encontrado. - - - Ocorreu um erro ao tentar aceitar licenças do Android - - - Falha ao aceitar licenças do Android: SDK do Android não encontrado - - - Falha ao aceitar licenças do Android: SDK do Java não encontrado - - - Falha ao aceitar licenças do Android: cmdline-tools não encontrado - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.resx deleted file mode 100644 index cbed730e388..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Component installation failed - - - Failure to load component properties file - - - No suitable component archive found. - - - An error occurred trying to accept Android licenses - - - Accept Android licenses failed: Android SDK not found - - - Accept Android licenses failed: Java SDK not found - - - Accept Android licenses failed: cmdline-tools not found - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ru.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ru.resx deleted file mode 100644 index 64e260b60a8..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.ru.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Сбой установки компонента - - - Не удалось загрузить файл свойств компонента - - - Подходящий архив компонентов не найден. - - - Произошла ошибка при попытке принять лицензии Android - - - Не удалось принять лицензии Android: пакет SDK для Android не найден - - - Не удалось принять лицензии Android: пакет SDK для Java не найден - - - Не удалось принять лицензии Android: инструменты командной строки не найдены - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.tr.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.tr.resx deleted file mode 100644 index d8e1e647c10..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.tr.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Bileşen yükleme işlemi başarısız oldu - - - Bileşen özellikleri dosyası yüklenemedi - - - Uygun bileşen arşivi bulunamadı. - - - Android lisansları kabul edilmeye çalışılırken hata oluştu - - - Android lisansları kabul edilemedi: Android SDK bulunamadı - - - Android lisansları kabul edilemedi: Java SDK bulunamadı - - - Android lisansları kabul edilemedi: cmdline-tools bulunamadı - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.zh-Hans.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.zh-Hans.resx deleted file mode 100644 index b8003c18edd..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.zh-Hans.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 组件安装失败 - - - 无法加载组件属性文件 - - - 找不到合适的组件存档。 - - - 尝试接受 Android 许可证时出错。 - - - 接受 Android 许可证失败: 找不到 Android SDK - - - 接受 Android 许可证失败: 找不到 Java SDK - - - 接受 Android 许可证失败: 找不到 cmdline-tools - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.zh-Hant.resx b/src/Xamarin.Installer.AndroidSDK/Properties/Resources.zh-Hant.resx deleted file mode 100644 index 9bd9bbf05f5..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Properties/Resources.zh-Hant.resx +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 元件安裝失敗 - - - 無法載入元件內容檔案 - - - 找不到適合的元件保存。 - - - 嘗試接受 Android 授權時發生錯誤 - - - 接受 Android 授權失敗: 找不到 Android SDK - - - 接受 Android 授權失敗: 找不到 JAVA SDK - - - 接受 Android 授權失敗: 找不到 Cmdline-tools - - \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK.csproj b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK.csproj deleted file mode 100644 index a62ec7972dd..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK.csproj +++ /dev/null @@ -1,94 +0,0 @@ - - - - $(NoWarn);CA1305;CS1591 - - - netstandard2.0 - 12 - false - WINDOWS;$(DefineConstants) - false - $(MicrosoftAndroidSdkOutDir) - - - bin\Debug\Xamarin.Installer.AndroidSDK.xml - - - bin\Release\Xamarin.Installer.AndroidSDK.xml - - - - - true - $(CodeSigningFile) - - - Xamarin.Installer.AndroidSDK - Assembly for Xamarin.Installer.AndroidSDK - - - - - - Properties\AssemblyInfoTemplate.cs - - - True - True - Resources.resx - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - TargetFramework=netstandard2.0 - - - - - - - - runtime - All - - - 1.0.0 - - - - - - - - - - - - - $(MSBuildThisFileDirectory)..\..\build-tools\android-platform-support\version.txt - - - - - - - - - - - Microsoft400 - - - Microsoft400 - - - - - diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidAddonDependencyInfo.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidAddonDependencyInfo.cs deleted file mode 100644 index e83e57b20fa..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidAddonDependencyInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -namespace Xamarin.Installer.AndroidSDK -{ - class AndroidAddonDependencyInfo - { - public string ApiLevel { get; set; } - public string NameId { get; set; } - public string NameDisplay { get; set; } - public string VendorId { get; set; } - public string VendorDisplay { get; set; } - public bool Unsure { get; set; } - } -} - diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidComponentType.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidComponentType.cs deleted file mode 100644 index bbb5fbfb33f..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidComponentType.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// Android component type. This serves as an easier way to find what type an instance of - /// represents. - /// - public enum AndroidComponentType - { - /// - /// Component is an addon - /// - Addon, - - /// - /// Component is an extra addition to the SDK - /// - Extra, - - /// - /// A generic component - /// - Generic, - - /// - /// A Maven component - /// - Maven, - - /// - /// An API level (platform) component - /// - Platform, - - /// - /// A source component - /// - Source, - - /// - /// A system image component - /// - SystemImage, - - /// - /// Unknown type of the component - /// - Unknown = 1000 - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidExtensions.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidExtensions.cs deleted file mode 100644 index 345e9419507..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - static class AndroidExtensions - { - public static bool GetPkgRevision (this IDictionary props, out string original, out AndroidRevision parsed, string packageName = null) - { - original = null; - parsed = null; - - packageName = packageName.SafeTrim (); - if (!String.IsNullOrEmpty (packageName)) - packageName = String.Format ("'{0}' ", packageName); - - if (props == null) { - Logger.Debug ("No properties object, cannot obtain Android package {0}revision", packageName); - return false; - } - - string rev; - if (!props.GetProperty("Pkg.Revision", out rev) || String.IsNullOrEmpty (rev)) { - Logger.Debug ("Android package {0}has no revision defined", packageName); - return false; - } - - original = rev; - var arev = new AndroidRevision (rev, false); - parsed = arev.IsValid ? arev : null; - - return parsed != null; - } - - public static Version TryParseAsAndroidVersion (this string av, bool returnDefaultZeros = false) - { - if (String.IsNullOrEmpty (av)) - goto returnDefault; - - if (av.IndexOf ('.') < 0) { - int v; - - if (!Int32.TryParse (av, out v)) { - Logger.Info ("Version is not an integer: {0}", av); - goto returnDefault; - } - - return new Version (v, 0).CloneFillWithZeros (); - } - - Version ver; - if (!Version.TryParse (av, out ver)) { - Logger.Info ("Package revision is not a valid version: {0}", av); - goto returnDefault; - } - - return ver.CloneFillWithZeros (); - - returnDefault: - return returnDefaultZeros ? new Version (0, 0, 0, 0) : null; - } - } -} \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidManifestType.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidManifestType.cs deleted file mode 100644 index 7eb6a76b3b0..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidManifestType.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// Author: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// Android manifest type. - /// - public enum AndroidManifestType - { - /// - /// New (as of 2016) Google repository manifest format (e.g. http://dl-ssl.google.com/android/repository/repository2-1.xml) - /// - GoogleV2, - - /// - /// Xamarin manifest format (https://aka.ms/AndroidManifestFeed/d17-12) - /// - Xamarin, - - /// - /// Doesn't access the Internet at all. Instead it looks for local repositories and attempts to read information about - /// all the installed components. The returned information can (and will) be incomplete - information about channels is - /// unavailable for locally installed packages, as well as download URLs of the archives. Care must be taken when - /// accessing properties so that no null reference exceptions are thrown. - /// - Local, - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidRevision.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidRevision.cs deleted file mode 100644 index a639b6cfe4f..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidRevision.cs +++ /dev/null @@ -1,354 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Text; - -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// Represents Android component revision. Only the component is guaranteed to be present. - /// - public sealed class AndroidRevision : IEquatable , IComparable - { - /// - /// Gets the major revision number - /// - /// Major revision number - public int Major { get; private set; } - - /// - /// Gets the minor revision number. Value is valid if it's equal or higer than zero. - /// - /// Minor revision number - public int Minor { get; private set; } - - /// - /// Gets the micro revision number. Value is valid if it's equal or higer than zero. - /// - /// Micro revision number - public int Micro { get; private set; } - - /// - /// Gets the minor preview number. Value is valid if it's equal or higer than zero. - /// - /// Preview revision number - public int Preview { get; private set; } - - /// - /// Indicates whether or not this revision instance represents a valid revision - /// - /// true if valid; otherwise, false. - public bool IsValid => Major > 0; - - /// - /// If set to true, indicates that should consider comparing only - /// the and properties. - /// - /// true to compare only major and minor components; otherwise, false. - public bool ConsiderOnlyMajorMinor { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// Major revision number (required, must be higher than or equal to zero) - /// Minor revision number (optional) - /// Micro revision number (optional) - /// Preview revision number (optional) - /// If set to true throw an exception if revision is invalid. - public AndroidRevision (int major, int minor = -1, int micro = -1, int preview = -1, bool throwIfInvalid = true) - { - Init (major, minor, micro, preview, throwIfInvalid); - } - - /// - /// Initializes a new instance of the class. Attempts to - /// parse the revision string passed in the parameter. - /// - /// Revision string to parse - /// If set to true throw an exception if revision is invalid. - public AndroidRevision (string rev, bool throwIfInvalid = true) - { - if (String.IsNullOrEmpty (rev)) - goto setDefault; - - if (rev.IndexOf ('.') < 0) { - int v; - - if (!Int32.TryParse (rev, out v)) { - Logger.Info ($"Version is not an integer: {rev}"); - goto setDefault; - } - - Init (v, throwIfInvalid: throwIfInvalid); - return; - } - - Version ver; - if (!Version.TryParse (rev, out ver)) { - Logger.Info ($"Package revision is not a valid version: {rev}"); - goto setDefault; - } - - Init (ver.Major, ver.Minor, ver.Build, ver.Revision, throwIfInvalid); - return; - - setDefault: - Init (0, throwIfInvalid: throwIfInvalid); - } - - public AndroidRevision (AndroidRevision other, bool throwIfInvalid = true) - { - if (other == null) - throw new ArgumentNullException (nameof (other)); - Init (other.Major, other.Minor, other.Micro, other.Preview, throwIfInvalid); - } - - void Init (int major, int minor = -1, int micro = -1, int preview = -1, bool throwIfInvalid = true) - { - if (major < 0 && throwIfInvalid) - throw new ArgumentOutOfRangeException(nameof(major), "Must not be less than zero"); - - Major = EnsureValidValue (major); - Minor = EnsureValidValue (minor); - Micro = EnsureValidValue (micro); - Preview = EnsureValidValue (preview); - } - - int EnsureValidValue (int value) - { - if (value < 0) - return -1; - return value; - } - - /// - /// Returns a that represents the current in the standard - /// dotted format. - /// - /// A that represents the current . - public override string ToString () - { - var sb = new StringBuilder (); - sb.Append (Major); - AppendValue (Minor, sb); - AppendValue (Micro, sb); - AppendValue (Preview, sb); - - return sb.ToString (); - } - - void AppendValue (int value, StringBuilder sb) - { - if (value < 0) - return; - sb.Append ('.'); - sb.Append (value); - } - - /// - /// Determines whether the specified is equal to the - /// current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public bool Equals (AndroidRevision other) - { - if (other == null) - return false; - - if (ReferenceEquals (this, other)) - return true; - - if (Major != other.Major) - return false; - - if (Minor != other.Minor) - return false; - - if (ConsiderOnlyMajorMinor) - return true; - - if (Micro != other.Micro) - return false; - - return Preview == other.Preview; - } - - public bool EqualsValid(AndroidRevision other) - { - if (other == null) - return false; - - if (ReferenceEquals(this, other)) - return true; - - if (!IsValid || !other.IsValid) - return false; - - if (Major != other.Major) - return false; - - if (Minor == -1 || other.Minor == -1) - return true; - if (Minor != other.Minor) - return false; - - if (Micro == -1 || other.Micro == -1) - return true; - if (Micro != other.Micro) - return false; - - if (Preview == -1 || other.Preview == -1) - return true; - return Preview == other.Preview; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidRevision); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = Major.GetHashCode (); - hashCode = hashCode.XorWith (Minor); - hashCode = hashCode.XorWith (Micro); - return hashCode.XorWith (Preview); - } - - /// - /// Compares this instance of to another one. - /// - /// - /// - /// - /// 1if this instance is bigger than - /// - /// - /// 0if this instance is equal to - /// - /// - /// -1if this instance is smaller than - /// - /// "> - /// Other. - public int CompareTo (AndroidRevision other) - { - if (other == null) - return 1; - - if (Major != other.Major) - return Major > other.Major ? 1 : -1; - - if (Minor != other.Minor) - return Minor > other.Minor ? 1 : -1; - - if (Micro != other.Micro) - return Micro > other.Micro ? 1 : -1; - - if (Preview != other.Preview) - return Preview > other.Preview ? 1 : -1; - - return 0; - } - - /// - /// Determines whether a specified instance of is equal to - /// another specified . - /// - /// The first to compare. - /// The second to compare. - /// true if rev1 and rev2 are equal; otherwise, false. - public static bool operator == (AndroidRevision rev1, AndroidRevision rev2) - { - if (Object.ReferenceEquals (rev1, null)) { - return Object.ReferenceEquals (rev2, null); - } - - return rev1.Equals (rev2); - } - - /// - /// Determines whether a specified instance of is not equal - /// to another specified . - /// - /// The first to compare. - /// The second to compare. - /// true if rev1 and rev2 are not equal; otherwise, false. - public static bool operator != (AndroidRevision rev1, AndroidRevision rev2) - { - return !(rev1 == rev2); - } - - /// - /// Determines whether one specified is lower than another - /// specfied . - /// - /// The first to compare. - /// The second to compare. - /// true if rev1 is lower than rev2; otherwise, false. - public static bool operator < (AndroidRevision rev1, AndroidRevision rev2) - { - if (rev1 == null) - throw new ArgumentNullException (nameof (rev1)); - return rev1.CompareTo (rev2) < 0; - } - - /// - /// Determines whether one specified is lower than or equal - /// to another specfied . - /// - /// The first to compare. - /// The second to compare. - /// true if rev1 is lower than or equal to rev2; otherwise, false. - public static bool operator <= (AndroidRevision rev1, AndroidRevision rev2) - { - if (rev1 == null) - throw new ArgumentNullException (nameof (rev1)); - return rev1.CompareTo (rev2) <= 0; - } - - /// - /// Determines whether one specified is greater than - /// another specfied . - /// - /// The first to compare. - /// The second to compare. - /// true if rev1 is greater than rev2; otherwise, false. - public static bool operator > (AndroidRevision rev1, AndroidRevision rev2) - { - return rev2 < rev1; - } - - /// - /// Determines whether one specified is greater than or - /// equal to another specfied . - /// - /// The first to compare. - /// The second to compare. - /// true if rev1 is greater than or equal to rev2; otherwise, false. - public static bool operator >= (AndroidRevision rev1, AndroidRevision rev2) - { - return rev2 <= rev1; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKComponentInstallationResult.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKComponentInstallationResult.cs deleted file mode 100644 index 70696d21450..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKComponentInstallationResult.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; - -namespace Xamarin.Installer.AndroidSDK -{ - public class AndroidSDKComponentInstallationResult - { - public enum States - { - None, - UserCancelled, - DownloadError, - InstallationError, - UninstallationError, - DownloadedSuccessfully, - InstalledSuccessfully, - UninstalledSuccessfully, - Success, - - LicensesNotAccepted, - LicensesAccepted, - LicensesNotRequired, - LicensesAcceptanceFailed - } - - public bool Success { get; set; } - public States State { get; set; } - - public Exception Exception { get; set; } - - public AndroidSDKComponentInstallationResult (bool success, Exception exception = null) - : this (success ? States.Success : States.None, exception, success) - { - } - - public AndroidSDKComponentInstallationResult (States state, Exception exception = null, bool? success = null) - { - State = state; - Exception = exception; - Success = success.HasValue ? success.Value : state.IsSuccessful (); - } - - /// - /// Use instead if you need to handle null values - /// - public override string ToString () - { - return this.ToReadableString (); - } - } - - public static class AndroidSDKComponentInstallationResultExtensions - { - public static bool IsSuccessful(this AndroidSDKComponentInstallationResult.States state) - { - return state == AndroidSDKComponentInstallationResult.States.Success - || state == AndroidSDKComponentInstallationResult.States.DownloadedSuccessfully - || state == AndroidSDKComponentInstallationResult.States.InstalledSuccessfully - || state == AndroidSDKComponentInstallationResult.States.UninstalledSuccessfully - || state == AndroidSDKComponentInstallationResult.States.LicensesAccepted - || state == AndroidSDKComponentInstallationResult.States.LicensesNotRequired; - } - - /// - /// This method supports null input values - /// - public static string ToReadableString (this AndroidSDKComponentInstallationResult result) - { - return result == null ? "undefined" : - (result.Success ? "success" - : ( - "fail" + (!String.IsNullOrEmpty (result.Exception?.Message) ? $": \"{result.Exception.Message}\"" : String.Empty) - )) + $" ({result.State})"; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKContext.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKContext.cs deleted file mode 100644 index c2be0dce8ae..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKContext.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; - -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - public class AndroidSDKContext - { - static readonly object instanceCreationLock = new object (); - - public static readonly AndroidSDKContext Instance; - - public AndroidSDKPlatform Platform { get; set; } - - public string HostArch { get; set; } - - public string BaseTemporaryDirectory { get; set; } - - public string UserName { - get { - if (CommonUtilities.Helpers == null) - throw new InvalidOperationException ("Internal error: CommonUtilities.Helpers must be initialized first"); - if (String.IsNullOrEmpty (CommonUtilities.Helpers.UserName)) - throw new InvalidOperationException ("Internal error: CommonUtilities.Helpers.UserName must have a valid value"); - return CommonUtilities.Helpers.UserName; - } - } - - // Just a convenience to make initialization more straightforward - public string ProductName { - get { return CommonUtilities.ProductName; } - set { CommonUtilities.ProductName = value; } - } - - static AndroidSDKContext () - { - lock (instanceCreationLock) { - if (Instance != null) - return; - - Instance = new AndroidSDKContext { - BaseTemporaryDirectory = Path.Combine(Path.GetTempPath(), "Xamarin"), - Platform = DeterminePlatform(), - HostArch = DetermineHostArch() - }; - } - } - - static AndroidSDKPlatform DeterminePlatform () - { - switch (Environment.OSVersion.Platform) { - case PlatformID.MacOSX: - return AndroidSDKPlatform.Mac; - - // We only care about distinction between OSX and Linux, since that's the only - // difference that matters in the Android SDK repository context - case PlatformID.Unix: - return IsRunningOnMac () ? AndroidSDKPlatform.Mac : AndroidSDKPlatform.Linux; - - default: - return AndroidSDKPlatform.Windows; // another simplification that'll do - } - } - - static string DetermineHostArch() - { - switch (RuntimeInformation.OSArchitecture) - { - case Architecture.X86: - return "x86"; - case Architecture.X64: - return "x64"; - case Architecture.Arm64: - return "aarch64"; - default: - return ""; - } - } - - [DllImport ("libc")] - static extern int uname (IntPtr buf); - - //From Managed.Windows.Forms/XplatUI - static bool IsRunningOnMac () - { - IntPtr buf = IntPtr.Zero; - try { - buf = Marshal.AllocHGlobal (8192); - // This is a hacktastic way of getting sysname from uname () - if (uname (buf) == 0) { - string os = Marshal.PtrToStringAnsi (buf); - if (os == "Darwin") - return true; - } - } catch { - // ignore - } finally { - if (buf != IntPtr.Zero) - Marshal.FreeHGlobal (buf); - } - return false; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKInstaller.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKInstaller.cs deleted file mode 100644 index f6e9a433318..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKInstaller.cs +++ /dev/null @@ -1,810 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Xml.Linq; - -using Xamarin.Android.Tools; -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.AndroidSDK.Xamarin; -using Xamarin.Installer.AndroidSDK.GoogleV2; -using Xamarin.Installer.AndroidSDK.LocalSDK; -using Xamarin.Installer.Common; -using Xamarin.Installer.AndroidSDK.Manager; -using System.Threading.Tasks; -using System.Threading; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// Android SDK installer class is the class to be used by the client software to perform all the - /// operations of updating or installing the SDK. - /// - public class AndroidSDKInstaller : IParserErrorHandler - { - List discoveredInstances; - StringComparer filesystemComparer; - StringComparison filesystemComparison; - Uri _manifestURL; - Uri _googleAddonsListURL; - Uri _googleRepositoryBaseURL; - bool _useManifestCaching; - string defaultAndroidSdkPath; - string[] allAndroidSdkPaths; - string defaultJavaSdkPath; - bool installationPathsDiscovered; - - /// - /// Initializes a new instance of the class. The caller is - /// required to pass an instance of class that implements the interface. - /// - /// Instance of a class implementing the IHelpers interface - /// AndroidManifestType.Xamarin if the installer is to use the - /// Xamarin Android SDK manifest, AndroidManifestType.GoogleV1 or AndroidManifestType.GoogleV2 - /// to use the official Google Android SDK manifest - /// URL of the repository manifest (optional) - /// Google repository only: URL of the addon manifest (optional) - /// Google repository only: base URL of the repository - /// If true, load local manifest when offline - /// Instance of a class implementing the interface (optional) - public AndroidSDKInstaller (IHelpers helpers, AndroidManifestType manifestType = AndroidManifestType.Xamarin, Uri manifestURL = null, Uri googleAddonsListURL = null, Uri googleRepositoryBaseURL = null, bool useManifestCaching = false, ILicensesStorage licensesStorage = null) - { - CommonUtilities.Helpers = helpers ?? new Helper(); - AndroidManifestType = manifestType; - - _manifestURL = manifestURL; - _googleAddonsListURL = googleAddonsListURL; - _googleRepositoryBaseURL = googleRepositoryBaseURL; - _useManifestCaching = useManifestCaching; - - LicensesStorage = licensesStorage ?? new AndroidLicensesStorage(); - - CreateRepository (manifestType, manifestURL, googleAddonsListURL, googleRepositoryBaseURL, useManifestCaching); - - filesystemComparer = helpers.IsCaseSensitiveFileSystem ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase; - filesystemComparison = helpers.IsCaseSensitiveFileSystem ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; - } - - void EnsureInstallationPathsDiscovered () - { - if (installationPathsDiscovered) - return; - - AndroidSdkInfo.DiscoverInstallationPaths (out defaultAndroidSdkPath, out allAndroidSdkPaths, out defaultJavaSdkPath, - logger: (level, message) => Logger.Debug ($"[{level}] {message}")); - installationPathsDiscovered = true; - } - - public Repository Repository { get; private set; } - - public ILicensesStorage LicensesStorage { get; private set; } - - public bool IgnoreArchiveChecksumErrors { get; set; } - - /// - /// Raised whenever the installer wants to show a message to the user. Used only by the Install* - /// family of methods. - /// - public event EventHandler InstallationProgress; - - /// - /// Gets the repository manifest URL as detected and used by the current installer instance. - /// - /// The repository manifest URL - public Uri RepositoryManifestURL { - get { return Repository?.ManifestURL; } - } - - /// - /// After calling this list will contain all the instances of Android SDK - /// detected on the system. Note that if there are no instances found a default one will be created - /// and stored in this list. - /// - /// The discovered Android SDK instances. - public IList DiscoveredSdkInstances { - get { return discoveredInstances; } - } - - /// - /// Gets list of all the channels retrieved from the various repository manifests. Currently all of the - /// Android SDK manifests defined the same 4 channels () but it is possible that - /// there might be differences between manifests in the future. - /// - /// The channels. - public IList Channels { - get { return Repository?.Channels?.Values?.ToList (); } - } - - /// - /// Sets or gets the Android manifest type for this instance (see ) - /// - public AndroidManifestType AndroidManifestType { get; } - - /// - /// Gets the repository state. If true, it is using local manifest, - /// and should be updated as soon as connection is established. - /// - public bool IsOffline => Repository.IsOffline; - - void CreateRepository (AndroidManifestType manifestType, Uri manifestURL, Uri googleAddonsListURL, Uri googleRepositoryBaseURL, bool useManifestCaching) - { - switch (manifestType) { - case AndroidManifestType.Xamarin: - Repository = new XamarinRepository (manifestURL, useManifestCaching); - break; - - case AndroidManifestType.GoogleV2: - Repository = new GoogleV2Repository (this, manifestURL, googleAddonsListURL, googleRepositoryBaseURL, useManifestCaching); - break; - - case AndroidManifestType.Local: - Repository = new LocalSDKRepository (this); - break; - - default: - throw new InvalidOperationException ($"Unsupported manifest type {manifestType}"); - } - } - - /// - /// Given a full filesystem path attempts to find and return a corresponding instance. - /// - /// The instance corresponding to the path. - /// Full path for which to find a corresponding SDK instance. If null, default path will be used. - public AndroidSdkInstance FindInstance (string forPath) - { - if (forPath == null) { - EnsureInstallationPathsDiscovered (); - forPath = defaultAndroidSdkPath; - } - - if (String.IsNullOrEmpty (forPath)) - throw new ArgumentException ("must not be an empty string", nameof (forPath)); - - string path = Path.GetFullPath (forPath); - if (discoveredInstances == null || discoveredInstances.Count == 0) { - return null; - } - - return discoveredInstances.FirstOrDefault (sdk => string.Equals (sdk.Path, path, filesystemComparison)); - } - - /// - /// - /// Refreshes the state of all the components given a particular Android SDK . By default the method - /// doesn't re-download or re-parse the manifest(s) but instead it performs detection of each of the components in the - /// instance, thus updating their state. If, however, is set to true the repository manifests, - /// if any, will be fetched and reparsed. - /// - /// - /// If is true then the may have its set of components changed - new - /// ones can be added and old ones can be changed (only their metadata will change, the component instance won't change). - /// - /// - /// - /// If is true then the method will start a full detection cycle. This means that the - /// will be modified - all of its components will be replaced with fresh instances. This is to ensure that - /// the metadata in the components is 100% accurate. By default full detection is not performed. - /// - /// - /// Android SDK instance - /// Perform update from the local filesystem, if true, update from remote manifests otherwise - /// If true, perform full detection of all the components after refreshing the instance - public void RefreshState (AndroidSdkInstance instance, bool localOnly = true, bool performFullDetection = false) - { - if (instance == null) - throw new ArgumentNullException (nameof (instance)); - if (!localOnly) - { - try - { - Repository.Parse(); - } - catch (Exception e) - { - LogParserError("AndroidSDK.RefreshState", e); - return; - } - } - Repository.Refresh (instance); - - if (performFullDetection) - DetectSdkComponents (instance); - } - - /// - /// Downloads the current Android SDK repository manifest () and uses it to disover/detect - /// all instances of Android SDK on the system. It uses the system-dependent default location as well as the locations stored - /// in the paths discovered by . Additionally, it can include extra paths passed in - /// the list. If no Android SDK instance is detected on the system a default one will be created. - /// All the discovered instances are returned by the property. - /// - /// If is set to true (the default), the discovered instances replace the ones currently stored in - /// the list returned by the property. Otherwise the newly discovered instances are appended - /// to the list. - /// - /// The method returns true if detection was successful, false to indicate a "soft" error (one which lets the caller - /// retry the operation, most likely a networking issue) and it can throw exceptions for "hard" errors. - /// - /// Custom Android SDK locations (optional). - /// Perform detection from scratch if set to true (optional) - /// Handler to be called whenever any component in the SDK instance changes its state - public bool Discover (List sdkLocations = null, bool fromScratch = true, EventHandler instanceComponentStatusChangeHandler = null) - { - if (fromScratch || !Repository.Parsed) { - if (fromScratch) - CreateRepository (AndroidManifestType, _manifestURL, _googleAddonsListURL, _googleRepositoryBaseURL, _useManifestCaching); - try - { - Repository.Parse(); - } - catch (Exception e) - { - LogParserError("AndroidSDK.Discover", e); - return false; - } - } - - var sdkInstances = new Dictionary (filesystemComparer); - if (!fromScratch && discoveredInstances != null) { - discoveredInstances.ForEach (instance => { - if (instance == null || sdkInstances.ContainsKey (instance.Path)) - return; - sdkInstances [instance.Path] = instance; - }); - } - - var sdkPaths = new List (); - - EnsureInstallationPathsDiscovered (); - sdkPaths.AddRange (allAndroidSdkPaths); - - if (sdkLocations != null) - sdkPaths.AddRange (sdkLocations); - - - sdkPaths = sdkPaths.Distinct ().ToList (); - - string defaultPath = defaultAndroidSdkPath ?? sdkPaths.FirstOrDefault (); - foreach (string path in sdkPaths) { - if (String.IsNullOrEmpty (path)) - continue; - string asdkPath = Path.GetFullPath (path); - if (sdkInstances.ContainsKey (asdkPath)) - continue; - - var sdkInstance = new AndroidSdkInstance { - Path = asdkPath, - IsDefault = string.Equals (path, defaultPath, filesystemComparison) - }; - if (instanceComponentStatusChangeHandler != null) { - sdkInstance.ComponentStatusChanged -= instanceComponentStatusChangeHandler; - sdkInstance.ComponentStatusChanged += instanceComponentStatusChangeHandler; - } - - DetectSdkComponents (sdkInstance); - - sdkInstances [asdkPath] = sdkInstance; - } - - if (fromScratch || discoveredInstances == null) - discoveredInstances = sdkInstances.Values.ToList (); - else { - sdkInstances.Values.ToList ().ForEach (instance => { - if (discoveredInstances.Contains (instance)) - return; - discoveredInstances.Add (instance); - }); - } - if (discoveredInstances.Count == 1) - discoveredInstances [0].Selected = true; - else if (discoveredInstances.Any () && !discoveredInstances.Any (item => item.Selected)) { - // Make sure we have a selected sdk in any case as the interaction is optional - // Select default location if its valid, select sdk with latest version otherwise - var defaultInstance = discoveredInstances.FirstOrDefault (item => item.IsDefault); - if (defaultInstance != null && (defaultInstance.Version.Major > 0 || !discoveredInstances.Any (item => item.Version.Major > 0))) - defaultInstance.Selected = true; - else - discoveredInstances.OrderByDescending (item => item.Version).First ().Selected = true; - } - - return true; - } - - /// - /// Gets the license with the ID specified in . The ID usually comes from - /// - /// - /// The license identified by or an empty string if license with this ID is not found. - /// License identifier. Required, must not be null - public string GetLicense (string licenseId) - { - if (licenseId == null) - throw new ArgumentNullException (nameof (licenseId)); - - return Repository.GetLicense (licenseId)?.Text; - } - - /// - /// Returns a list of licenses for all the components passed in the - /// parameter or, if it's null or empty, for all the outdated components in the specified - /// . - /// - /// List of licenses or null if no licenses were available - /// Android SDK instance. - /// List of components to install (optional) - public IList GetLicenses (AndroidSdkInstance instance, IList componentsToInstall = null) - { - if (instance == null) - throw new ArgumentNullException (nameof (instance)); - - IList < IAndroidComponent > components = null; - if (componentsToInstall == null || componentsToInstall.Count == 0) - components = instance.Components.AllOutdated (); - - if (components == null || components.Count == 0) - return null; - - var ret = new List (); - foreach (IAndroidComponent component in components) { - License license = component?.License; - if (license == null || ret.Contains (license)) - continue; - ret.Add (license); - } - - return ret.Count > 0 ? ret : null; - } - - /// - /// Gets a list of download items for all of the components passed in the parameter. After a - /// successful download the calling party must set to the on-disk path of the - /// downloaded file thus marking the instance as installable. - /// - /// List of archives to download - /// List of components to get download items for - public IList GetDownloadItems (IList components) - { - if (components == null || components.Count == 0) - return null; - - var ret = new List (); - foreach (IAndroidComponent component in components.Where (c => c != null && c.Archives != null && c.Archives.Count > 0)) { - ret.AddRange (component.Archives.Where (a => a != null && a.Url != null).Select (a => ResetForDownload (a))); - } - return ret; - - Archive ResetForDownload (Archive archive) - { - archive.DownloadedFilePath = null; - return archive; - } - } - - /// - /// Gets a list of download items for all the outdated or missing components in the passed . After a - /// successful download the calling party must set to the on-disk path of the - /// downloaded file thus marking the instance as installable. The method considers - /// before - /// - /// List of archives to download - /// Android SDK instance - /// If true, include missing components - public IList GetDownloadItems (AndroidSdkInstance instance, bool includeMissing = false) - { - if (instance == null) - return null; - IList components = instance.ComponentsForInstallation ?? instance.Components; - return GetDownloadItems (includeMissing ? components?.AllOutdatedOrMissing () : components?.AllOutdated ()); - } - - void OnInstallationProgress (bool isInitialEvent, float progress, string format, params object[] args) - { - if (InstallationProgress == null) - return; - - string message; - if (format == null) - message = String.Empty; - else if (args == null || args.Length == 0) - message = format; - else - message = String.Format (format, args); - InstallationProgress (this, new InstallationProgressEventArgs { Message = message, Progress = progress, IsInitialEvent = isInitialEvent }); - } - - /// - /// - /// Gets the set of components available for installation given the particular . - /// If is null or empty, the outdated components from the - /// will be considered for inclusion in the set. If the - /// parameter is null or empty, only the default channel (stable) packages will be considered. - /// - /// - /// Each component's dependencies will be added to the resulting set. It is possible that certain components - /// (for instance build tools or emulators) will be found in the returned set more than once because they match - /// the criteria (e.g. all the included versions are higher than the one detected on the system) or because they - /// are dependent upon by one or more of the other components. - /// - /// - /// Caller must decide which packages to eventually install if there are duplicates in the returned set. - /// - /// - /// List of components that are candidates for installation in the given SDK instance - /// Android SDK instance - /// Components to install. - /// Allowed channels. - public IList GetInstallationSet (AndroidSdkInstance instance, IList componentsToInstall = null, HashSet allowedChannels = null) - { - if (instance == null) - throw new ArgumentNullException (nameof (instance)); - - if (componentsToInstall == null || componentsToInstall.Count == 0) - componentsToInstall = instance.Components.AllOutdated (); - - if (componentsToInstall.Count == 0) - return null; - - if (allowedChannels == null || allowedChannels.Count == 0) { - allowedChannels = new HashSet { - Repository.DefaultChannel - }; - } - - var components = new List (); - foreach (IAndroidComponent c in componentsToInstall) { - AddComponentToSet (instance, c, components, allowedChannels); - } - - return components; - } - - /// - /// Performs installation of all the components in the specified . The - /// parameter must not be null or empty and it must contain all the components the hosting application needs to install - no dependency - /// checking is performed by this method. It is advised to call the method prior to calling this one. - /// Before installing anything the method checks all the archives in all the passed components, including checksum verification, to make sure they are installable. - /// Checksum failures can be explicitly ignored with ; other archive validation still applies. - /// If any invalid archive is found no installation is done. This is to prevent partially successful installations, potentially breaking the SDK - /// instance. If is set to true and an invalid archive is found then the method - /// will throw an exception, otherwise it will return without performing installation. All the issues are logged. - /// - /// Android SDK instance. - /// Components to install - /// Throw an exception if any component with invalid archives is found, if set to true - /// Progress monitor (optional) - public void Install (AndroidSdkInstance instance, IList componentsToInstall, bool throwIfInvalidComponentsFound = true, - IProgressMonitor monitor = null) - { - if (instance == null) - throw new ArgumentNullException (nameof (instance)); - - if (componentsToInstall == null) - throw new ArgumentNullException (nameof (componentsToInstall)); - - //throw new Exception("A test install inner exception."); - - if (componentsToInstall.Count == 0) - return; - - // This is a separate step so that we can report all the issues at the same time as well as prevent - // installing of any components if even a single archive isn't valid. - bool haveArchiveIssues = false; - foreach (IAndroidComponent c in componentsToInstall) { - // If it happens simply ignore the component silently - if (c == null || c.Archives == null || c.Archives.Count == 0) - continue; - - bool haveInvalidArchives = false; - bool checkPlatform = !(c.Info is AndroidComponentInfoSystemImage); - foreach (Archive a in c.Archives) { - if (a == null || !a.WasDownloaded || a.IsInstallable (checkPlatform: checkPlatform)) - continue; - if (IgnoreArchiveChecksumErrors && a.IsInstallable (verifyChecksum: false, checkPlatform: checkPlatform)) { - Logger.Action ($"Continuing installation of Android SDK archive '{a.Url}' despite a checksum verification failure because the checksum override is enabled. The archive may be damaged or modified."); - continue; - } - haveInvalidArchives = true; - } - - if (haveInvalidArchives) { - haveArchiveIssues = true; - Logger.Warning ($"Android SDK component '{c.DetailedDescription}' reports issues with downloaded archive(s)"); - } - } - - if (haveArchiveIssues) { - Logger.Error ($"Certain Android SDK components encountered issues with the downloaded archives"); - if (throwIfInvalidComponentsFound) - throw new InvalidOperationException ("Found issues with one or more Android SDK Components. Unable to continue."); - return; - } - - foreach (IAndroidComponent c in componentsToInstall) - InstallComponent (c, instance, monitor); - } - - /// - /// Removes the components listed in from the specified . - /// - /// Android SDK instance. - /// Components to remove - public void Remove (AndroidSdkInstance instance, IList componentsToRemove) - { - if (instance == null) - throw new ArgumentNullException (nameof (instance)); - - if (componentsToRemove == null) - throw new ArgumentNullException (nameof (componentsToRemove)); - - //throw new Exception("Uninstall inner test exception."); - - if (componentsToRemove.Count == 0) - return; - - foreach (IAndroidComponent c in componentsToRemove) { - if (c == null) - continue; - - Repository.Remove (c, instance.Path); - } - } - - void AddComponentToSet (AndroidSdkInstance instance, IAndroidComponent component, List componentSet, HashSet allowedChannels) - { - if (component == null) { - Logger.Debug ("Skipping null component"); - return; - } - if (!component.ForceInstallation && component.Present && !component.NeedsUpdate) { - Logger.Debug ($"Skipping component '{component.DetailedDescription}' as it is already present and up-to-date"); - return; - } - if (allowedChannels != null && !allowedChannels.Contains (component.Channel)) { - var channels = string.Join (", ", allowedChannels.Select (c => c.Name)); - Logger.Debug ($"Skipping component '{component.DetailedDescription}' in channel '{component.Channel?.Name}' as it is not in the allowed channels ({channels})"); - return; - } - if (componentSet.Contains (component)) { - Logger.Debug ($"Skipping component '{component.DetailedDescription}' as it is already in the set"); - return; - } - - Logger.Debug ($"Adding component '{component.DetailedDescription}'"); - componentSet.Add (component); - - string hostOS = AndroidUtilities.GetPlatformOS (); - if (component.Dependencies != null) { - foreach (Dependency dep in component.Dependencies) { - if (dep == null || String.IsNullOrEmpty (dep.Path)) - continue; - Logger.Debug ($"{component.DetailedDescription} depends on: '{dep.Path}'{GetMinimumRevisionString (dep)}"); - IList deps = instance.Components.AllWithPath (dep.Path, dep.MinRevision); - if (deps == null || deps.Count == 0) { - Logger.Debug ($"{component.DetailedDescription}: dependency package '{dep.Path}' not found"); - continue; - } - string instances = GetPluralForm (deps.Count, "instance", "instances"); - Logger.Debug ($"{component.DetailedDescription}: found {deps.Count} {instances} of '{dep.Path}'"); - foreach (IAndroidComponent dc in deps) { - if (dc == component) - continue; - AddComponentToSet (instance, dc, componentSet, allowedChannels); - } - } - } - } - - string GetPluralForm (int count, string singular, string plural) - { - return count == 1 ? singular : plural; - } - - string GetMinimumRevisionString (Dependency dep) - { - if (dep?.MinRevision == null) - return ", any revision"; - return $", minimum revision {dep.MinRevision}"; - } - - void InstallComponent (IAndroidComponent c, AndroidSdkInstance instance, IProgressMonitor monitor = null) - { - if (c == null || (!c.ForceInstallation && c.Present && !c.NeedsUpdate) || (c.Archives == null || c.Archives.Count == 0)) - return; - var component = c as BasePackage; - if (component == null) - throw new InvalidOperationException ($"Internal error: unexpected component type {c.GetType ()}"); - - int installSubComponentIndex = 0; - bool isMonitorWithTotalProgress; - if (monitor is MonitorWithTotalProgress wrapperMonitor) - isMonitorWithTotalProgress = wrapperMonitor.IsMonitorWithTotalProgress; - else if (monitor is IProgressMonitorWithTotalProgress) { - monitor = new MonitorWithTotalProgress (monitor, 1); - isMonitorWithTotalProgress = true; - } else - isMonitorWithTotalProgress = false; - - if (isMonitorWithTotalProgress && ((MonitorWithTotalProgress) monitor).IsMonitorWithTotalProgress) { - ((MonitorWithTotalProgress) monitor).State = MonitorWithTotalProgress.States.Install; - ((MonitorWithTotalProgress) monitor).SubComponentsCount = component.Archives.Count; - } - - // In theory there should be just a single archive in each component, but we never know really... - foreach (Archive archive in component.Archives) { - // We can skip the checksum verification, it was done earlier - // Don't check platform if the component is system-image - if (!archive.IsInstallable (false, checkPlatform: !(component.Info is AndroidComponentInfoSystemImage))) - continue; - - string progressMsgFormat = CommonUtilities.Helpers.GetString ("Installing {0}"); - string componentName = component.DetailedDescription; - - InstallationProgressEventArgs.InstallationProgressActionDelegate progressCallback = - delegate (float progress) { - //Logger.Debug($"[InstallationProgressActionDelegate] will report progress: {progress}"); - OnInstallationProgress (false, progress, progressMsgFormat, componentName); - monitor?.ReportProgress ((long) progress); - }; - - OnInstallationProgress (true, 0f, progressMsgFormat, componentName); - - monitor?.BeginStep (String.Format (progressMsgFormat, componentName), 100); - - if (isMonitorWithTotalProgress && ((MonitorWithTotalProgress) monitor).IsMonitorWithTotalProgress) { - ((MonitorWithTotalProgress) monitor).SubComponentIndex = installSubComponentIndex++; - } - - Repository.Install (component, archive.DownloadedFilePath, instance.Path, progressCallback); - monitor?.EndStep (new AndroidSDKComponentInstallationResult (AndroidSDKComponentInstallationResult.States.InstalledSuccessfully)); - } - } - - void DetectSdkComponents (AndroidSdkInstance sdkInstance) - { - if (String.IsNullOrEmpty (sdkInstance.Path)) - throw new InvalidOperationException ("Internal error: Android SDK instance without associated path"); - - Logger.Debug ($"Detecting Android SDK in '{sdkInstance.Path}'"); - Repository.Detect (sdkInstance); - - var sourcePropsFileName = "source.properties"; - string path = Path.Combine (sdkInstance.Path, Constants.ComponentPaths.Tools, Constants.RequiredComponentVersions.RequiredCommandLineToolsVersion, sourcePropsFileName); - if (!File.Exists (path)) { - path = Path.Combine (sdkInstance.Path, Constants.ComponentPaths.ToolsObsolete, sourcePropsFileName); - } - - var props = AndroidUtilities.ReadAndroidProperties (path); - - if (!props.GetPkgRevision (out string origRev, out AndroidRevision instv)) { - sdkInstance.Version = new AndroidRevision (0, 0, 0, 0); - sdkInstance.VersionString = "r0"; - Logger.Debug ("Could not retrieve Pkg.Revision from {0}, r0 assumed", path); - return; - } - sdkInstance.VersionString = "r" + origRev; - sdkInstance.Version = instv; - - // The paths currently overlap with the contents of the tools package, but this can change hence the - // code duplication - List sdkExistenceCheckPaths; - switch (AndroidSDKContext.Instance.Platform) { - case AndroidSDKPlatform.Linux: - case AndroidSDKPlatform.Mac: - sdkExistenceCheckPaths = new List { - Path.Combine (Constants.ComponentPaths.Tools, Constants.RequiredComponentVersions.RequiredCommandLineToolsVersion, "bin", "avdmanager"), - Path.Combine (Constants.ComponentPaths.Tools, Constants.RequiredComponentVersions.RequiredCommandLineToolsVersion, "bin", "lint"), - Path.Combine (Constants.ComponentPaths.Tools, Constants.RequiredComponentVersions.RequiredCommandLineToolsVersion, "bin", "sdkmanager"), - }; - break; - - case AndroidSDKPlatform.Windows: - sdkExistenceCheckPaths = new List { - Path.Combine (Constants.ComponentPaths.Tools, Constants.RequiredComponentVersions.RequiredCommandLineToolsVersion, "bin", "avdmanager.bat"), - Path.Combine (Constants.ComponentPaths.Tools, Constants.RequiredComponentVersions.RequiredCommandLineToolsVersion, "bin", "lint.bat"), - Path.Combine (Constants.ComponentPaths.Tools, Constants.RequiredComponentVersions.RequiredCommandLineToolsVersion, "bin", "sdkmanager.bat"), - }; - break; - - default: - throw new InvalidOperationException ("Unsupported platform"); - } - - bool someFound = AndroidUtilities.CheckWheterFilesExist (sdkInstance.Path, "Android SDK Core", sdkExistenceCheckPaths, out double percentFound); - if (!someFound || percentFound < 100.0) { - if (someFound) - Logger.Info ("'Android SDK Core' has less than 100% of its files on disk. Update is necessary."); - } - } - - void IParserErrorHandler.OnRecoverableError (ParserErrorLevel recommendedLevel, Uri documentUrl, XElement element, string message) - { - switch (recommendedLevel) { - case ParserErrorLevel.Debug: - Logger.Debug (message); - break; - - case ParserErrorLevel.Info: - Logger.Info (message); - break; - - case ParserErrorLevel.Error: - case ParserErrorLevel.Warning: - Logger.Warning (message); - break; - - default: - goto case ParserErrorLevel.Info; - } - } - - void IParserErrorHandler.OnFatalError (Uri documentUrl, XElement element, string message) - { - Logger.Error (message); - } - - static void LogParserError(string whereItHappened, Exception e) - { - Logger.Error($"[{whereItHappened}]: Failure parsing Android manifest: {e.Message}"); - Logger.Error($"[{whereItHappened}]: This is usually due to bad XML in one or more of the SDK manifests."); - } - - /// - /// Returns if the license was accepted in this Android SDK - /// - /// Android SDK instance. - /// license to check - /// true if the license is accepted, false otherwise - public bool IsLicenseAccepted(AndroidSdkInstance instance, License license) - { - if (instance == null || license == null) - { - return false; - } - - return this.LicensesStorage.IsLicenseAccepted(instance.Path, license); - } - - /// - /// Accept licenses - /// - /// Android SDK instance. - /// list of licenses to accept - /// cancellation token - /// log file path - /// path to java sdk - /// if true, throws an exception if license validation fails - public Task AcceptLicensesAsync(AndroidSdkInstance instance, IEnumerable licenses, CancellationToken token, string javaSdkPath = null, string logPath = null, bool throwsErrorIfValidationFailed = false) - { - if (instance != null) { - var androidSdkPath = instance.Path; - var javaPath = javaSdkPath; - if (string.IsNullOrEmpty (javaPath)) { - EnsureInstallationPathsDiscovered (); - javaPath = defaultJavaSdkPath; - } - - // try use the preferred cmdline-tools - var cmdlineToolsRoot = Path.Combine(androidSdkPath, Constants.ComponentPaths.Tools); - var cmdLineToolsPath = Path.Combine(cmdlineToolsRoot, Constants.RequiredComponentVersions.RequiredCommandLineToolsVersion); - var cmdLineToolsPropertiesFilePath = Path.Combine(cmdLineToolsPath, "source.properties"); - if (!File.Exists(cmdLineToolsPropertiesFilePath)) - { - // try use the latest cmdline-tools installed - if (Directory.Exists(cmdlineToolsRoot)) - { - cmdLineToolsPath = Directory.EnumerateDirectories(cmdlineToolsRoot).OrderBy(d => Path.GetFileName(d)).LastOrDefault(); - } - else - { - cmdLineToolsPath = string.Empty; - } - } - - return LicensesStorage.AcceptLicensesAsync(androidSdkPath, javaPath, cmdLineToolsPath, licenses, token, logPath, throwsErrorIfValidationFailed); - } - - return Task.CompletedTask; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKPlatform.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKPlatform.cs deleted file mode 100644 index 70ed0748ce8..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSDKPlatform.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Xamarin.Installer.AndroidSDK -{ - public enum AndroidSDKPlatform - { - Linux, - Mac, - Windows, - Any, - Unknown - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSdkInstance.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSdkInstance.cs deleted file mode 100644 index c6a503d4b8e..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSdkInstance.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.Collections.Generic; -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// Describes a single Android SDK instance on the user's machine - /// - public sealed class AndroidSdkInstance - { - ulong? downloadSize; - IList components; - - /// - /// Occurs when component status changes. - /// - public event EventHandler ComponentStatusChanged; - - /// - /// List of all the components that can be or are installed in this SDK instance. - /// The caller needs to determine whether or not they desire all of them to be actually installed. - /// - /// List of all SDK components for this instance - public IList Components { - get { return components; } - internal set { - components = value; - HookComponentEvents (components); - } - } - - /// - /// A convenience property to store only components selected for installation as opposed to - /// which has all the components loaded from the manifest. This - /// property is used by the unified installer. - /// - /// The components for installation. - public IList ComponentsForInstallation { get; set; } - - /// - /// Indicates whether this instance corresponds to the default Android SDK location - /// - /// true if this instance corresponds to the default Android SDK location; otherwise, false. - public bool IsDefault { get; internal set; } - - /// - /// Indicates whether this instance corresponds to the official Android SDK location. Official location is, in fact, found - /// only on Windows when the .exe Android SDK installer was used. - /// - /// true if this instance is official; otherwise, false. - public bool IsOfficial { get; internal set; } - - /// - /// Indicates whether this instance corresponds to a location specified by the user in the Unified Installer. - /// - /// true if this instance is user location; otherwise, false. - public bool IsUserLocation { get; set; } - - /// - /// Path to this instance's directory on disk. Note that the directory might not exist yet. - /// - /// Instance directory path. - public string Path { get; internal set; } - - /// - /// Indicates whether this instance has been selected as the one to install to. Used by the unified installer. - /// - /// true if selected; otherwise, false. - public bool Selected { get; set; } - - /// - /// Android SDK version in string (unparsed) form. It may include additional information in additon to the actual - /// revision/version number. - /// - /// The version string. - public string VersionString { get; internal set; } - - /// - /// Parsed Android SDK version. This is parsed from and includes only the numeric part. - /// - /// The version. - public AndroidRevision Version { get; internal set; } - - /// - /// Gets a value indicating whether this needs any updates. - /// - /// true if needs update; otherwise, false. - public bool NeedsUpdate => Components != null && Components.AnyOutdated (); - - internal AndroidSdkInstance () - {} - - /// - /// Computes the total download size of all components - /// passed in the parameter. If is false - /// (the default) a cached value will be returned for all calls following the first one. If - /// is null or empty, all the outdated components in this instance will be included in calculation. - /// - /// The total download size. - /// Components to install (optional) - /// Use cached value of the download size if true. - public ulong GetDownloadSize (IList componentsToInstall = null, bool refresh = false) - { - if (!refresh && downloadSize.HasValue) - return downloadSize.Value; - - if (componentsToInstall == null || componentsToInstall.Count == 0) - componentsToInstall = Components.AllOutdated (); - - downloadSize = 0; - if (componentsToInstall.Count == 0) - return 0; - - ulong ret = 0; - foreach (IAndroidComponent component in componentsToInstall) { - if (component == null) - continue; - foreach (Archive archive in component.Archives) { - if (archive == null) - continue; - ret += archive.Size; - } - }; - - downloadSize = ret; - return ret; - } - - void HookComponentEvents (IList components) - { - if (components == null || components.Count == 0) - return; - - foreach (IAndroidComponent c in components) { - c.StatusChanged -= OnStatusChanged; - c.StatusChanged += OnStatusChanged; - } - } - - void OnStatusChanged (object sender, AndroidComponentStatusChangeEventArgs args) - { - if (ComponentStatusChanged == null) - return; - - ComponentStatusChanged (this, args); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSystemImageAbi.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSystemImageAbi.cs deleted file mode 100644 index 16b8b641501..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidSystemImageAbi.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// Android SDK System Image ABI - /// - public enum AndroidSystemImageAbi - { - /// - /// System Image for the x86 architecture - /// - X86, - - /// - /// System Image for the x86_64 architecture - /// - X86_64, - - /// - /// System Image for the MIPS architecture - /// - Mips, - - /// - /// System Image for the arm-v7a architecture - /// - ARMV7a, - - /// - /// System Image for the arm64-v8a architecture - /// - ARM64V8a, - - /// - /// Represents any ABI - /// - Any = 1000 - } -} - diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidUtilities.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidUtilities.cs deleted file mode 100644 index d9287a76dd0..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/AndroidUtilities.cs +++ /dev/null @@ -1,492 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; -using System.Xml; - -using Xamarin.Installer.AndroidSDK.Properties; -using Xamarin.Installer.Common; -using Xamarin.Installer.AndroidSDK.Common; -using System.Text; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// A collection of Android SDK utilities - /// - public static class AndroidUtilities - { - const string PLACEHOLDER_DELIMITER = "|"; - - static readonly Regex ndkNameRegex = new Regex (@"android-ndk-r(?\d+)(?\w*)-\w*", RegexOptions.Compiled); - - /// - /// Parses a string with embedded placeholders to render a full directory path. Placeholders are - /// placed between pipe characters and their names come from members of the - /// enumeration. - /// - /// pattern to parse - /// - public static string ParseDirectoryWithSpecialFolderPlaceholders (string dirPattern) - { - dirPattern = dirPattern.SafeTrim (); - if (String.IsNullOrEmpty (dirPattern)) - return String.Empty; - - string ret = dirPattern; - - // A dumb way, but it's all we need - foreach (string name in Enum.GetNames (typeof (Environment.SpecialFolder))) { - string ph = PLACEHOLDER_DELIMITER + name + PLACEHOLDER_DELIMITER; - // We only replace the placeholder at the start of the value, since that's the only place where it makes sense - if (ret.IndexOf (ph, StringComparison.Ordinal) != 0) - continue; - ret = ret.Replace (ph, Environment.GetFolderPath ((Environment.SpecialFolder)Enum.Parse (typeof (Environment.SpecialFolder), name))); - } - - return ret; - } - - /// - /// Reads Java properties from the specified file - /// - /// path to the properties file - /// collection of property names and values. - public static Dictionary ReadAndroidProperties (string sourcePropertiesPath) - => ReadAndroidProperties (sourcePropertiesPath, detectEncodingFromByteOrderMarks: false); - - internal static Dictionary ReadAndroidProperties (string sourcePropertiesPath, bool detectEncodingFromByteOrderMarks) - { - if (String.IsNullOrEmpty (sourcePropertiesPath) || !File.Exists (sourcePropertiesPath)) - return new Dictionary (StringComparer.Ordinal); - - try { - using (var fs = File.Open (sourcePropertiesPath, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (var reader = new StreamReader (fs, Encoding.GetEncoding (28591), detectEncodingFromByteOrderMarks)) { - return ReadProperties (reader); - } - } catch (Exception ex) { - Logger.Exception ("Failed to read Android properties from {0}", ex, sourcePropertiesPath); - throw new InvalidOperationException (Resources.FailedToLoadSourceProperties, ex); - } - } - - static Dictionary ReadProperties (TextReader reader) - { - var properties = new Dictionary (StringComparer.Ordinal); - int ch = reader.Read (); - while (ch != -1) { - if (IsWhitespace (ch) || ch is '\r' or '\n') { - ch = reader.Read (); - continue; - } - if (ch is '#' or '!') { - while (ch != -1 && ch is not ('\r' or '\n')) - ch = reader.Read (); - continue; - } - - string key = ReadPart (isKey: true); - SkipWhitespace (); - if (ch is '=' or ':') { - ch = reader.Read (); - SkipWhitespace (); - } - properties [key] = ReadPart (isKey: false); - } - return properties; - - string ReadPart (bool isKey) - { - var part = new StringBuilder (); - while (ch != -1 && ch is not ('\r' or '\n') && !(isKey && (IsWhitespace (ch) || ch is '=' or ':'))) { - if (ch != '\\') { - part.Append ((char)ch); - ch = reader.Read (); - continue; - } - - ch = reader.Read (); - if (ch is '\r' or '\n') { - if (ch == '\r' && reader.Peek () == '\n') - reader.Read (); - ch = reader.Read (); - SkipWhitespace (); - continue; - } - if (ch == 'u') { - int value = 0; - for (int i = 0; i < 4; i++) { - int digit = reader.Read (); - // Preserve the legacy reader's acceptance of letters beyond hexadecimal digits. - int digitValue = digit switch { - >= '0' and <= '9' => digit - '0', - >= 'a' and <= 'z' => digit - 'a' + 10, - >= 'A' and <= 'Z' => digit - 'A' + 10, - _ => throw new FormatException ("Invalid Unicode character."), - }; - value = (value << 4) + digitValue; - } - part.Append ((char)value); - } else { - // A trailing escape historically decodes end of input as U+FFFF. - part.Append (ch switch { - 't' => '\t', - 'r' => '\r', - 'n' => '\n', - 'f' => '\f', - _ => (char)ch, - }); - } - ch = reader.Read (); - } - return part.ToString (); - } - - void SkipWhitespace () - { - while (IsWhitespace (ch)) - ch = reader.Read (); - } - - static bool IsWhitespace (int character) => character is ' ' or '\t' or '\f'; - } - - /// - /// Installs (unpacks) the specified Android SDK ZIP archive () in the directory - /// specified in the parameter. You can pass more path segments following the - /// parameter, they will be used to construct the final path rooted at - /// - /// name of the archive/component, for informational purposes - /// path to the ZIP archive - /// top directory in which to install the archive - /// optional path segments to append to to form the archive installation path - /// - public static bool InstallArchive (string name, string archivePath, string targetBasePath, params string[] targetPaths) - { - return InstallArchive (name, archivePath, false, targetBasePath, targetPaths); - } - - /// - /// Installs (unpacks) the specified Android SDK ZIP archive () in the directory - /// specified in the parameter. You can pass more path segments following the - /// parameter, they will be used to construct the final path rooted at - /// If is set to true, the archive is unzipped without first creating a backup of the possibly existing - /// target directory. This is used to install the main (distribution) archive of the Android SDK. - /// - /// name of the archive/component, for informational purposes - /// path to the ZIP archive - /// archive is the main/root archive of the Android SDK - /// top directory in which to install the archive - /// optional path segments to append to to form the archive installation path - /// - public static bool InstallArchive (string name, string archivePath, bool mainArchive, string targetBasePath, params string[] targetPaths) - { - string destDir; - return InstallArchive (out destDir, name, archivePath, mainArchive, false, targetBasePath, targetPaths); - } - - /// - /// Installs (unpacks) the specified Android SDK ZIP archive () in the directory - /// specified in the parameter. You can pass more path segments following the - /// parameter, they will be used to construct the final path rooted at - /// If is set to true, the archive is unzipped without first creating a backup of the possibly existing - /// target directory. This is used to install the main (distribution) archive of the Android SDK. - /// If is false then the method copies only the contents of the toplevel directory of the archive, instead of the - /// entire contents of the archive. This is used with Android SDK archives who contain a single root directory and their target directory on disk is named differently. - /// - /// set to the destination directory on exit - /// name of the archive/component, for informational purposes - /// path to the ZIP archive - /// archive is the main/root archive of the Android SDK - /// include the archive's top-level directory in the copy if true, copy just its contents otherwise - /// top directory in which to install the archive - /// optional path segments to append to to form the archive installation path - /// true if copy was successful, false otherwise - public static bool InstallArchive (out string destinationDirectory, string name, string archivePath, bool mainArchive, bool includeZipRootInCopy, string targetBasePath, params string[] targetPaths) - { - destinationDirectory = null; - Logger.Info ("Installing Android archive '{0}'", name); - if (String.IsNullOrEmpty ("archivePath")) - throw new ArgumentNullException ("archivePath"); - if (String.IsNullOrEmpty (targetBasePath)) - throw new ArgumentNullException ("targetBasePath"); - - var rnd = new Random (); - string componentUnzippedPath = null; - - // A small race here but I think we can accept the risks :) - string temporaryPath = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ()); - try { - componentUnzippedPath = CommonUtilities.Helpers.Unzip (temporaryPath, archivePath, AndroidSDKContext.Instance.UserName).RemoveTrailingDirectorySeparator (); - } catch (Exception ex) { - Logger.Exception (String.Format ("Exception caught while unzipping '{0}' in '{1}'", archivePath, temporaryPath), ex); - componentUnzippedPath = null; - } - - if (String.IsNullOrEmpty (componentUnzippedPath)) { - Logger.SetOperationStatus (OperationStatus.Failure); - Logger.Error ("Attempt to unzip Android archive '{0}' found in {1} failed.", name, archivePath); - return false; - } - - Logger.Debug ("Android archive '{0}' unpacked in directory '{1}'", name, componentUnzippedPath); - destinationDirectory = CombinePaths (targetBasePath, targetPaths); - if (includeZipRootInCopy) - destinationDirectory = Path.Combine (destinationDirectory, Path.GetFileName (componentUnzippedPath)); - Logger.Debug ("Archive's destination path: {0}", destinationDirectory); - string oldDestinationPath = null; - - if (!mainArchive && Directory.Exists (destinationDirectory)) { - oldDestinationPath = destinationDirectory + ".old" + rnd.Next (Int32.MaxValue); - Logger.Info ("Moving old directory '{0}' to '{1}'", destinationDirectory, oldDestinationPath); - CommonUtilities.MoveDirectory (destinationDirectory, oldDestinationPath); - } - - bool ret = true; - try { - int idx = destinationDirectory.LastIndexOf (Path.DirectorySeparatorChar); - string leadingPath; - if (idx > 1) - leadingPath = destinationDirectory.Substring (0, idx); - else - leadingPath = destinationDirectory; - - if (!Directory.Exists (leadingPath)) { - Logger.Info ("Creating Android component's parent path '{0}'", leadingPath); - Directory.CreateDirectory (leadingPath); - } - Logger.Info ("Moving component to its destination path."); - - CommonUtilities.MoveDirectory (componentUnzippedPath, destinationDirectory, overwrite: true); - } catch (Exception e) { - ret = false; - Logger.Exception ("Failure to move component to its destination path. Exception was thrown.", e); - if (!String.IsNullOrEmpty (oldDestinationPath) && Directory.Exists (oldDestinationPath)) { - Logger.Error ("Attempting to clean up."); - Logger.Error ("Trying to remove directory '{0}'", destinationDirectory); - CommonUtilities.DeleteDirectoryRecursively (destinationDirectory); - - try { - CommonUtilities.MoveDirectory (oldDestinationPath, destinationDirectory); - } catch (Exception ex) { - // ignore - Logger.Exception ("Failed to rename directory '{0}' to '{1}'", ex, oldDestinationPath, destinationDirectory); - } - } - } - - bool logError = false; - Exception rex = null; - try { - CommonUtilities.DeleteDirectoryRecursively (temporaryPath); - if (!String.IsNullOrEmpty (oldDestinationPath)) - logError = !CommonUtilities.DeleteDirectoryRecursively (oldDestinationPath); - } catch (Exception e) { - logError = true; - ret = false; - rex = e; - // ignore - } - if (logError) { - string message = String.Format ("Failed to remove old destination directory '{0}'. User will have to remove it manually.", oldDestinationPath); - if (rex != null) - Logger.Exception (message, rex); - else - Logger.Error (message); - } - - return ret; - } - - internal static string CombinePaths (string targetBasePath, params string[] targetPaths) - { - if (targetPaths == null || targetPaths.Length == 0) - return targetBasePath; - else { - var allPaths = new List (); - allPaths.Add (targetBasePath); - allPaths.AddRange (targetPaths); - return Path.Combine (allPaths.ToArray ()); - } - } - - internal static bool ParsePlatformVersion (string source, out Version version, out string versionTag) - { - version = null; - versionTag = String.Empty; - - source = (source ?? String.Empty).Trim (); - if (String.IsNullOrEmpty (source)) - return false; - - try { - if (source.Length >= 3) { // The minimum valid version is X.Y - version = Version.Parse (source); - return true; - } - } catch (FormatException) { - // ignore - google introduced version numbers with letters in them, we deal with it below - } - - string validVersion = null; - for (int i = 0; i < source.Length; i++) { - char ch = source[i]; - if (ch == '.' || Char.IsDigit (ch)) - continue; - - validVersion = source.Substring (0, i); - versionTag = source.Substring (i); - } - - if (!String.IsNullOrEmpty (validVersion)) - version = Version.Parse (validVersion); - - return true; - } - - public static string GetPlatformOS () - { - return PlatformToString (AndroidSDKContext.Instance.Platform); - } - - public static string PlatformToString (AndroidSDKPlatform platform) - { - switch (platform) { - case AndroidSDKPlatform.Linux: - return "linux"; - - case AndroidSDKPlatform.Mac: - return "macosx"; - - case AndroidSDKPlatform.Windows: - return "windows"; - - case AndroidSDKPlatform.Unknown: - case AndroidSDKPlatform.Any: - return String.Empty; - - default: - throw new InvalidOperationException ($"Unknown SDK platform: {platform}"); - } - } - - internal static AndroidSDKPlatform GetPlatformFromOS (string osName) - { - osName = osName?.Trim (); - if (String.IsNullOrEmpty (osName)) // Some archives aren't OS-specific - return AndroidSDKPlatform.Any; - - if (string.Equals (osName, "linux", StringComparison.OrdinalIgnoreCase)) - return AndroidSDKPlatform.Linux; - - if (string.Equals (osName, "macosx", StringComparison.OrdinalIgnoreCase)) - return AndroidSDKPlatform.Mac; - - if (string.Equals (osName, "windows", StringComparison.OrdinalIgnoreCase)) - return AndroidSDKPlatform.Windows; - - return AndroidSDKPlatform.Unknown; - } - - internal static bool CheckWheterFilesExist (string root, string ownerName, List paths, out double percentFound) - { - percentFound = 0; - int found = 0; - if (paths == null || paths.Count == 0) - return false; - - foreach (string p in paths) { - string path = p.SafeTrim (); - if (String.IsNullOrEmpty (path)) - continue; - path = Path.Combine (root, path); - if (File.Exists (path)) - found++; - else - Logger.Info ("File '{0}' not found for '{1}'", path, ownerName); - } - - if (found == 0) - return false; - - percentFound = ((double)found * 100.0) / (double)paths.Count; - - return true; - } - - internal static AndroidSystemImageAbi StringToAbi (string abi) - { - abi = abi.SafeTrim (); - if (String.IsNullOrEmpty (abi)) - return AndroidComponentInfoSystemImage.DefaultAbi; - - if (string.Equals ("arm64-v8a", abi, StringComparison.OrdinalIgnoreCase)) - return AndroidSystemImageAbi.ARM64V8a; - - if (string.Equals ("armeabi-v7a", abi, StringComparison.OrdinalIgnoreCase)) - return AndroidSystemImageAbi.ARMV7a; - - if (string.Equals ("mips", abi, StringComparison.OrdinalIgnoreCase)) - return AndroidSystemImageAbi.Mips; - - if (string.Equals ("x86", abi, StringComparison.OrdinalIgnoreCase)) - return AndroidSystemImageAbi.X86; - - if (string.Equals ("x86_64", abi, StringComparison.OrdinalIgnoreCase)) - return AndroidSystemImageAbi.X86_64; - - throw new ArgumentOutOfRangeException (String.Format ("Unknown ABI '{0}'", abi)); - } - - /// - /// Utility method to work around Google's decision not to include NDK version in the Android SDK repository manifest v11. Parsing is - /// performed with the assumption that the NDK archive name follows a certain convention that matches the - /// android-ndk-r(?<ver>\d+)(?<tag>\w*)-\w* regex. - /// - /// manifest XML element for the NDK node - /// namespace manager initialized for the repository manifest - /// Base URL to use when the NDK element has only relative URLs - /// receives the NDK release, if parse is successful (just the number) - /// receives the NDK release tag, if parse is successful (just the trailing non-digit characters) - public static void ParseNDKVersionFromGoogleManifest (XmlElement element, XmlNamespaceManager nsmgr, Uri baseURL, out string release, out string releaseTag) - { - // Conveniently, google don't include NDK version in the manifest, why bother? We'll need to try to parse - // the URL for name... - XmlNodeList urls = element.SelectNodes ("sdk:archives/sdk:archive/sdk:url", nsmgr); - if (urls == null || urls.Count == 0) - throw new InvalidOperationException ("Android SDK manifest has NDK element without URLs, unable to determine NDK version"); - - Uri url = null; - foreach (XmlNode n in urls) { - string uri; - var urlElement = n as XmlElement; - if (n == null) - continue; - uri = urlElement.InnerXml.SafeTrim (); - if (String.IsNullOrEmpty (uri)) - continue; - if (!Uri.TryCreate (uri, UriKind.RelativeOrAbsolute, out url)) - continue; - break; - } - - if (url == null) - throw new InvalidOperationException ("Android SDK manifest has NDK element without valid URLs, unable to determine NDK version"); - - if (!url.IsAbsoluteUri) - url = new Uri (baseURL, url); - - string ndkName = Path.GetFileName (url.LocalPath).SafeTrim (); - if (String.IsNullOrEmpty (ndkName)) - throw new InvalidOperationException ("Android SDK has NDK element without valid archive name in the URL, unable to determine NDK version"); - - Match match = ndkNameRegex.Match (ndkName); - if (!match.Success) - throw new InvalidOperationException ("Android SDK has NDK element with URLs in unsupported format, unable to determine NDK version"); - - release = match.Groups["ver"].Value; - releaseTag = match.Groups["tag"].Value; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfo.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfo.cs deleted file mode 100644 index 16a5ac1d580..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfo.cs +++ /dev/null @@ -1,156 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Xml; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Base class for all the types containing detailed information about specific component groups/kinds. - /// - public abstract class AndroidComponentInfo : IEquatable - { - /// - /// Gets the component type name. The name corresponds to the Google SDK remote package type, not the .NET one. - /// - /// Type name - public string Type { get; } - - /// - /// Gets the printable detailed description of the package type. - /// - /// Detailed type description - public string DetailedDescription => GetDetailedDescription (); - - /// - /// Initializes a new instance of the class. - /// - /// Type name (required to be not null and not empty). - protected AndroidComponentInfo (string type) - { - if (String.IsNullOrEmpty (type)) - throw new ArgumentException ("must not be null or empty", nameof (type)); - - Type = type; - } - - /// - /// Builds and returns the detailed description of the component type. - /// - /// Detailed type description - protected abstract string GetDetailedDescription (); - - internal void WritePackageXmlInfo (XmlWriter writer, Repository repository) - { - writer.WriteStartElement ("type-details"); - writer.WriteAttributeString ("xmlns", "xsi", null, repository.GetNamespaceUri ("xsi")); - writer.WriteAttributeString ("xsi", "type", null, Type); - - WritePackageXmlInfoDetails (writer, repository); - - writer.WriteEndElement (); // type-details - } - - /// - /// Writes XML representation of the package vendor data. - /// - /// XML writer - /// Vendor data - protected void WritePackageXmlVendor (XmlWriter writer, PackageVendor vendor) - { - writer.WriteStartElement ("vendor"); - writer.WriteStartElement ("id"); - writer.WriteString (vendor?.ID ?? String.Empty); - writer.WriteEndElement (); // id - - writer.WriteStartElement ("display"); - writer.WriteString (vendor?.Display ?? String.Empty); - writer.WriteEndElement (); // display - writer.WriteEndElement (); // vendor - } - - /// - /// Writes XML representation of the package tag data. - /// - /// XML Writer - /// Tag data - protected void WritePackageXmlTag (XmlWriter writer, PackageTag tag) - { - writer.WriteStartElement ("tag"); - writer.WriteStartElement ("id"); - writer.WriteString (tag?.ID ?? String.Empty); - writer.WriteEndElement (); // id - - writer.WriteStartElement ("display"); - writer.WriteString (tag?.Display ?? String.Empty); - writer.WriteEndElement (); // display - writer.WriteEndElement (); // tag - } - - internal virtual void WritePackageXmlInfoDetails (XmlWriter writer, Repository repository) - { - } - - /// - /// Determines whether the specified is equal - /// to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to - /// the current ; otherwise, false. - public bool Equals (AndroidComponentInfo other) - { - if (other == null) - return false; - - if (ReferenceEquals (this, other)) - return true; - - return string.Equals (Type, other.Type, StringComparison.Ordinal); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidComponentInfo); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - if (Type == null) - return hashCode; - - return hashCode.XorWith (Type.GetHashCode ()); - } - - /// - /// A helper to compare two strings. - /// - /// true, if strings are equal, false otherwise. - /// first string - /// second string - protected bool AreEqual (string one, string two) - { - if (one == null) - return two == null; - - return string.Equals (one, two, StringComparison.Ordinal); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoAddon.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoAddon.cs deleted file mode 100644 index 4279feef629..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoAddon.cs +++ /dev/null @@ -1,179 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Information about the addon Android component - /// - public class AndroidComponentInfoAddon : AndroidComponentInfo, IAndroidApiLevel, IEquatable - { - string detailedDescription; - - /// - /// Gets the API level. - /// - /// The API level. - public string ApiLevel { get; } - - /// - /// Gets the platform source code name. - /// - /// Platfor code name - public string CodeName { get; } - - /// - /// Gets the tag associated with the system image - /// - /// Package tag - public PackageTag Tag { get; } - - /// - /// Gets system image vendor information - /// - /// System image vendor - public PackageVendor Vendor { get; } - - /// - /// List of libraries shipped with this addon - /// - /// Libraries shipped with this addon - public IList Libraries { get; } - - internal AndroidComponentInfoAddon(string type, string apiLevel, string codeName, PackageTag tag, PackageVendor vendor, IList libraries) : base (type) - { - if (String.IsNullOrEmpty (apiLevel)) - throw new ArgumentException ("must not be null or empty", nameof (apiLevel)); - - ApiLevel = apiLevel; - CodeName = codeName; - Tag = tag; - Vendor = vendor; - Libraries = libraries; - } - - internal override void WritePackageXmlInfoDetails (XmlWriter writer, Repository repository) - { - writer.WriteStartElement ("api-level"); - writer.WriteString (ApiLevel ?? String.Empty); - writer.WriteEndElement (); // api-level - - writer.WriteStartElement ("codename"); - writer.WriteString (CodeName ?? String.Empty); - writer.WriteEndElement (); // codename - - WritePackageXmlVendor (writer, Vendor); - WritePackageXmlTag (writer, Tag); - - writer.WriteStartElement ("libraries"); - if (Libraries != null && Libraries.Count > 0) { - foreach (PackageLibrary lib in Libraries) { - if (lib == null) - continue; - writer.WriteStartElement ("library"); - writer.WriteAttributeString ("localJarPath", lib?.LocalJarPath ?? String.Empty); - writer.WriteAttributeString ("name", lib?.Name ?? String.Empty); - writer.WriteStartElement ("description"); - writer.WriteString (lib?.Description ?? String.Empty); - writer.WriteEndElement (); // description - writer.WriteEndElement (); // library - } - } - writer.WriteEndElement (); // libraries - } - - /// - /// Gets the detailed description of the component - /// - /// Description - protected override string GetDetailedDescription () - { - if (detailedDescription != null) - return detailedDescription; - - var desc = new List (); - if (!String.IsNullOrEmpty (ApiLevel)) - desc.Add ($"API {ApiLevel}"); - if (!String.IsNullOrEmpty (CodeName)) - desc.Add ($"\"{CodeName}\""); - if (!String.IsNullOrEmpty (Vendor?.Display)) - desc.Add ($"({Vendor.Display})"); - - if (desc.Count > 0) - detailedDescription = $"Addon: {String.Join (" ", desc)}"; - else - detailedDescription = String.Empty; - return detailedDescription; - } - - /// - /// Determines whether the specified is - /// equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal - /// to the current ; otherwise, false. - public bool Equals (AndroidComponentInfoAddon other) - { - if (!Equals ((AndroidComponentInfo)other)) - return false; - - if (!AreEqual (ApiLevel, other.ApiLevel)) - return false; - - if (Tag != other.Tag) - return false; - - if (Vendor != other.Vendor) - return false; - - if (!AreEqual (CodeName, other.CodeName)) - return false; - - return Libraries.AreEqual (other.Libraries); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidComponentInfoAddon); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (ApiLevel != null) - hashCode = hashCode.XorWith (ApiLevel.GetHashCode ()); - - if (CodeName != null) - hashCode = hashCode.XorWith (CodeName.GetHashCode ()); - - if (Tag != null) - hashCode = hashCode.XorWith (Tag.GetHashCode ()); - - if (Vendor != null) - hashCode = hashCode.XorWith (Vendor.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoExtra.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoExtra.cs deleted file mode 100644 index 3e225819f12..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoExtra.cs +++ /dev/null @@ -1,100 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Information about the extra Android component - /// - public class AndroidComponentInfoExtra : AndroidComponentInfo, IEquatable - { - string detailedDescription; - - /// - /// Gets system image vendor information - /// - /// System image vendor - public PackageVendor Vendor { get; } - - internal AndroidComponentInfoExtra (string type, PackageVendor vendor) : base (type) - { - Vendor = vendor; - } - - internal override void WritePackageXmlInfoDetails (XmlWriter writer, Repository repository) - { - WritePackageXmlVendor (writer, Vendor); - } - - /// - /// Gets the detailed description of the component - /// - /// Description - protected override string GetDetailedDescription () - { - if (detailedDescription != null) - return detailedDescription; - - var desc = new List (); - if (!String.IsNullOrEmpty (Vendor?.Display)) - desc.Add ($"({Vendor.Display})"); - - if (desc.Count > 0) - detailedDescription = $"Extra: {String.Join (" ", desc)}"; - else - detailedDescription = String.Empty; - return detailedDescription; - } - - /// - /// Determines whether the specified is - /// equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal - /// to the current ; otherwise, false. - public bool Equals (AndroidComponentInfoExtra other) - { - if (!Equals ((AndroidComponentInfo)other)) - return false; - - if (Vendor != other.Vendor) - return false; - return true; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidComponentInfoExtra); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (Vendor != null) - hashCode = hashCode.XorWith (Vendor.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoGeneric.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoGeneric.cs deleted file mode 100644 index 71e3debcda3..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoGeneric.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Information about a generic component. - /// -#pragma warning disable CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode() - public class AndroidComponentInfoGeneric : AndroidComponentInfo, IEquatable -#pragma warning restore CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode() - { - public AndroidComponentInfoGeneric (string type) : base (type) - {} - - /// - /// Builds and returns the detailed description of the component type. . - /// This override returns an empty string. - /// - /// Detailed type description - protected override string GetDetailedDescription () - { - return String.Empty; - } - - /// - /// Determines whether the specified is - /// equal to the current . - /// - /// The to compare with the current . - /// true if the specified is - /// equal to the current ; otherwise, false. - public bool Equals (AndroidComponentInfoGeneric other) - { - return Equals ((AndroidComponentInfo)other); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidComponentInfoGeneric); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoMaven.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoMaven.cs deleted file mode 100644 index 66e114dc684..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoMaven.cs +++ /dev/null @@ -1,100 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Information about the Maven Android component - /// - public class AndroidComponentInfoMaven : AndroidComponentInfo, IEquatable - { - string detailedDescription; - - /// - /// Gets system image vendor information - /// - /// System image vendor - public PackageVendor Vendor { get; } - - internal AndroidComponentInfoMaven (string type, PackageVendor vendor) : base (type) - { - Vendor = vendor; - } - - internal override void WritePackageXmlInfoDetails (XmlWriter writer, Repository repository) - { - WritePackageXmlVendor (writer, Vendor); - } - - /// - /// Gets the detailed description of the component - /// - /// Description - protected override string GetDetailedDescription () - { - if (detailedDescription != null) - return detailedDescription; - - var desc = new List (); - if (!String.IsNullOrEmpty (Vendor?.Display)) - desc.Add ($"({Vendor.Display})"); - - if (desc.Count > 0) - detailedDescription = $"Maven: {String.Join (" ", desc)}"; - else - detailedDescription = String.Empty; - return detailedDescription; - } - - /// - /// Determines whether the specified is - /// equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal - /// to the current ; otherwise, false. - public bool Equals (AndroidComponentInfoMaven other) - { - if (!Equals ((AndroidComponentInfo)other)) - return false; - - if (Vendor != other.Vendor) - return false; - return true; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidComponentInfoMaven); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (Vendor != null) - hashCode = hashCode.XorWith (Vendor.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoPlatform.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoPlatform.cs deleted file mode 100644 index c97d8c889fe..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoPlatform.cs +++ /dev/null @@ -1,162 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Information about the API level (platform) component - /// - public class AndroidComponentInfoPlatform : AndroidComponentInfo, IAndroidApiLevel,IEquatable - { - string detailedDescription; - - /// - /// Gets the API level - /// - /// The API level. - public string ApiLevel { get; } - - /// - /// Gets the platform code name. - /// - /// Platfor code name - public string CodeName { get; } - - /// - /// Gets the layout library API version - /// - /// Layout library API version - public string LayoutLibApi { get; } - - /// - /// Description of the API level. - /// - /// Platform description. - public string Description { get; internal set; } - - /// - /// Is the Platform API level a preview? - /// - /// if the Platform is not API stable. - public bool Preview { get; internal set; } - - internal AndroidComponentInfoPlatform (string type, string apiLevel, string codeName, string layoutLibApi) : base (type) - { - if (String.IsNullOrEmpty (apiLevel)) - throw new ArgumentException ("must not be null or empty", nameof (apiLevel)); - if (String.IsNullOrEmpty (layoutLibApi)) - throw new ArgumentException ("must not be null or empty", nameof (layoutLibApi)); - - ApiLevel = apiLevel; - CodeName = codeName; - LayoutLibApi = layoutLibApi; - } - - internal override void WritePackageXmlInfoDetails (XmlWriter writer, Repository repository) - { - writer.WriteStartElement ("api-level"); - writer.WriteString (ApiLevel ?? String.Empty); - writer.WriteEndElement (); // api-level - - writer.WriteStartElement ("codename"); - writer.WriteString (CodeName ?? String.Empty); - writer.WriteEndElement (); // codename - - writer.WriteStartElement ("preview"); - writer.WriteString (Preview.ToString ()); - writer.WriteEndElement (); // preview - - writer.WriteStartElement ("layoutlib"); - writer.WriteAttributeString ("api", ApiLevel ?? String.Empty); - writer.WriteEndElement (); // layoutlib - } - - /// - /// Gets the detailed description of the component - /// - /// Description - protected override string GetDetailedDescription () - { - if (detailedDescription != null) - return detailedDescription; - - var desc = new List (); - if (!String.IsNullOrEmpty (ApiLevel)) - desc.Add ($"API {ApiLevel}"); - if (!String.IsNullOrEmpty (CodeName)) - desc.Add ($"\"{CodeName}\""); - - if (desc.Count > 0) - detailedDescription = $"Platform: {String.Join (" ", desc)}"; - else - detailedDescription = String.Empty; - return detailedDescription; - } - - /// - /// Determines whether the specified is - /// equal to the current . - /// - /// The to compare with the current . - /// true if the specified is - /// equal to the current ; otherwise, false. - public bool Equals (AndroidComponentInfoPlatform other) - { - if (!Equals ((AndroidComponentInfo)other)) - return false; - - if (!AreEqual (ApiLevel, other.ApiLevel)) - return false; - - if (!AreEqual (CodeName, other.CodeName)) - return false; - - if (Preview != other.Preview) - return false; - - return AreEqual (LayoutLibApi, other.LayoutLibApi); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidComponentInfoPlatform); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (ApiLevel != null) - hashCode = hashCode.XorWith (ApiLevel.GetHashCode ()); - - if (CodeName != null) - hashCode = hashCode.XorWith (CodeName.GetHashCode ()); - - hashCode = hashCode.XorWith (Preview.GetHashCode ()); - - if (LayoutLibApi != null) - hashCode = hashCode.XorWith (LayoutLibApi.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoSource.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoSource.cs deleted file mode 100644 index 6fa54158b01..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoSource.cs +++ /dev/null @@ -1,122 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Information about the platform source code Android component - /// - public class AndroidComponentInfoSource : AndroidComponentInfo, IAndroidApiLevel, IEquatable - { - string detailedDescription; - - /// - /// Gets the API level - /// - /// The API level. - public string ApiLevel { get; } - - /// - /// Gets the platform source code name. - /// - /// Platfor code name - public string CodeName { get; } - - internal AndroidComponentInfoSource (string type, string apiLevel, string codeName) : base (type) - { - if (String.IsNullOrEmpty (apiLevel)) - throw new ArgumentException ("must not be null or empty", nameof (apiLevel)); - - ApiLevel = apiLevel; - CodeName = codeName; - } - - internal override void WritePackageXmlInfoDetails (XmlWriter writer, Repository repository) - { - writer.WriteStartElement ("api-level"); - writer.WriteString (ApiLevel ?? String.Empty); - writer.WriteEndElement (); // api-level - - writer.WriteStartElement ("codename"); - writer.WriteString (CodeName ?? String.Empty); - writer.WriteEndElement (); // codename - } - - /// - /// Gets the detailed description of the component - /// - /// Description - protected override string GetDetailedDescription () - { - if (detailedDescription != null) - return detailedDescription; - - var desc = new List (); - if (!String.IsNullOrEmpty (ApiLevel)) - desc.Add ($"API {ApiLevel}"); - if (!String.IsNullOrEmpty (CodeName)) - desc.Add ($"\"{CodeName}\""); - - if (desc.Count > 0) - detailedDescription = $"Platform Source: {String.Join (" ", desc)}"; - else - detailedDescription = String.Empty; - return detailedDescription; - } - - /// - /// Determines whether the specified is - /// equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal - /// to the current ; otherwise, false. - public bool Equals (AndroidComponentInfoSource other) - { - if (!Equals ((AndroidComponentInfo)other)) - return false; - - if (!AreEqual (ApiLevel, other.ApiLevel)) - return false; - - return AreEqual (CodeName, other.CodeName); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidComponentInfoSource); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (ApiLevel != null) - hashCode = hashCode.XorWith (ApiLevel.GetHashCode ()); - - if (CodeName != null) - hashCode = hashCode.XorWith (CodeName.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoSystemImage.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoSystemImage.cs deleted file mode 100644 index 9b593e82640..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentInfoSystemImage.cs +++ /dev/null @@ -1,187 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Information about the system image Android component - /// - public class AndroidComponentInfoSystemImage : AndroidComponentInfo, IAndroidApiLevel, IEquatable - { - /// - /// The default architecture - /// - public static readonly AndroidSystemImageAbi DefaultAbi = AndroidSystemImageAbi.X86; - - string detailedDescription; - - /// - /// System image ABI - /// - /// System image ABI - public AndroidSystemImageAbi Abi { get; } - - /// - /// Gets the textual version of the system image ABI - /// - /// Name of the ABI - public string AbiName { get; } - - /// - /// Gets the API level. - /// - /// The API level. - public string ApiLevel { get; } - - /// - /// Gets the platform source code name. - /// - /// Platfor code name - public string CodeName { get; } - - /// - /// Gets the tag associated with the system image - /// - /// Package tag - public PackageTag Tag { get; } - - /// - /// Gets system image vendor information - /// - /// System image vendor - public PackageVendor Vendor { get; } - - internal AndroidComponentInfoSystemImage (string type, AndroidSystemImageAbi abi, string abiName, string apiLevel, string codeName, PackageTag tag, PackageVendor vendor) : base (type) - { - if (String.IsNullOrEmpty (apiLevel)) - throw new ArgumentException ("must not be null or empty", nameof (apiLevel)); - - Abi = abi; - AbiName = abiName; - ApiLevel = apiLevel; - CodeName = codeName; - Tag = tag; - Vendor = vendor; - } - - internal override void WritePackageXmlInfoDetails (XmlWriter writer, Repository repository) - { - writer.WriteStartElement ("api-level"); - writer.WriteString (ApiLevel ?? String.Empty); - writer.WriteEndElement (); // api-level - - writer.WriteStartElement ("codename"); - writer.WriteString (CodeName ?? String.Empty); - writer.WriteEndElement (); // codename - - WritePackageXmlTag (writer, Tag); - WritePackageXmlVendor (writer, Vendor); - - writer.WriteStartElement ("abi"); - writer.WriteString (GetAbiManifestString ()); - writer.WriteEndElement (); // abi - } - - public string GetAbiManifestString () - { - return String.IsNullOrEmpty (AbiName) ? Abi.ToString ().ToLowerInvariant () : AbiName.ToLowerInvariant (); - } - - /// - /// Gets the detailed description of the component - /// - /// Description - protected override string GetDetailedDescription () - { - if (detailedDescription != null) - return detailedDescription; - - var desc = new List (); - desc.Add ($"{Abi}"); - if (!String.IsNullOrEmpty (ApiLevel)) - desc.Add ($"API {ApiLevel}"); - if (!String.IsNullOrEmpty (CodeName)) - desc.Add ($"\"{CodeName}\""); - if (!String.IsNullOrEmpty (Vendor?.Display)) - desc.Add ($"({Vendor.Display})"); - - detailedDescription = $"System Image: {String.Join (" ", desc)}"; - return detailedDescription; - } - - /// - /// Determines whether the specified - /// is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is - /// equal to the current ; - /// otherwise, false. - public bool Equals (AndroidComponentInfoSystemImage other) - { - if (!Equals ((AndroidComponentInfo)other)) - return false; - - if (Abi != other.Abi) - return false; - - if (!AreEqual (ApiLevel, other.ApiLevel)) - return false; - - if (Tag != other.Tag) - return false; - - if (Vendor != other.Vendor) - return false; - - if (!AreEqual (CodeName, other.CodeName)) - return false; - - return true; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as AndroidComponentInfoSystemImage); - } - - /// - /// Serves as a hash function for a - /// object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (ApiLevel != null) - hashCode = hashCode.XorWith (ApiLevel.GetHashCode ()); - - if (CodeName != null) - hashCode = hashCode.XorWith (CodeName.GetHashCode ()); - - if (Tag != null) - hashCode = hashCode.XorWith (Tag.GetHashCode ()); - - if (Vendor != null) - hashCode = hashCode.XorWith (Vendor.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentStatus.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentStatus.cs deleted file mode 100644 index 0df9722be07..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentStatus.cs +++ /dev/null @@ -1,74 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc (http://microsoft.com) -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Android component status. , - /// - /// - public enum AndroidComponentStatus - { - /// - /// Component detection started - /// - DetectionStarted, - - /// - /// Component detection completed - /// - DetectionEnded, - - /// - /// Component installation started - /// - InstallationStarted, - - /// - /// Component installation ended - /// - InstallationEnded, - - /// - /// Component archive unpacking started - /// - UnpackingStarted, - - /// - /// Component archive unpacking ended - /// - UnpackingEnded, - - /// - /// Component removal started - /// - RemovalStarted, - - /// - /// Component removal ended - /// - RemovalEnded, - - /// - /// Component verification started - /// - VerificationStarted, - - /// - /// Component verification started - /// - VerificationEnded, - - /// - /// Component metadata (presence, version etc) changed - /// - MetadataUpdated - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentStatusChangeEventArgs.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentStatusChangeEventArgs.cs deleted file mode 100644 index d2891ecff56..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidComponentStatusChangeEventArgs.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc (http://microsoft.com) -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Android component status change event arguments. - /// - public class AndroidComponentStatusChangeEventArgs : EventArgs - { - /// - /// Gets the new component status. - /// - /// The status. - public AndroidComponentStatus Status { get; } - - /// - /// Gets the component whose status changed - /// - /// The component. - public IAndroidComponent Component { get; } - - internal AndroidComponentStatusChangeEventArgs (AndroidComponentStatus status, IAndroidComponent component) - { - Component = component ?? throw new ArgumentNullException (nameof (component)); - Status = status; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidLicensesStorage.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidLicensesStorage.cs deleted file mode 100644 index d092e906ff4..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/AndroidLicensesStorage.cs +++ /dev/null @@ -1,457 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Xamarin.Installer.AndroidSDK.Properties; -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// AndroidLicensesStorage class has all the protocol to check if a License was accepted - /// - public class AndroidLicensesStorage : ILicensesStorage - { - /// - /// Returns the path where licenses acceptance are stored - /// - /// Android Sdk path - /// Directory path where the licenses acceptance are stored - protected virtual string GetLicensesPath(string androidSdkPath) - { - return string.IsNullOrWhiteSpace(androidSdkPath) || !Directory.Exists(androidSdkPath) ? null : Path.Combine(androidSdkPath, "licenses"); - } - - /// - /// Returns if the license was accepted in this Android SDK - /// - /// Android Sdk path - /// license to check - /// true if the license is accepted, false otherwise - public bool IsLicenseAccepted(string androidSdkPath, License license) - { - if (license == null || string.IsNullOrEmpty(license.ID)) - return false; - - var localLicensesPath = GetLicensesPath(androidSdkPath); - if(string.IsNullOrEmpty(localLicensesPath)) - return false; - - var licensePath = Path.Combine(localLicensesPath, license.ID); - if (!File.Exists(licensePath)) - return false; - - var storedLicenseHash = GetLicenseHash(licensePath); - return !string.IsNullOrEmpty(storedLicenseHash); - } - - protected virtual string GetLicenseHash(License license) - { - if (string.IsNullOrEmpty(license?.Text)) - { - return null; - } - - var licenseText = license.Text; -#pragma warning disable CA5350 - using (var hashAlgorithm = SHA1.Create()) // CodeQL [SM02196] Used to verify checksums provided by an external party. - { - var bytes = Encoding.UTF8.GetBytes(licenseText); - var hash = string.Concat(hashAlgorithm.ComputeHash(bytes).Select(x => x.ToString("x2"))); - return hash; - } -#pragma warning restore CA5350 - } - - protected virtual string GetLicenseHash(string licensePath) - { - return string.IsNullOrWhiteSpace(licensePath) || !File.Exists(licensePath) ? null : File.ReadAllText(licensePath); - } - - /// - /// Accept licenses using local storage - /// - /// Android Sdk path - /// Java Sdk path - /// specific cmdLine-tools path to use - /// list of licenses to accept - /// cancellation token - /// log file path - /// if true, throws an exception if license validation fails - public Task AcceptLicensesAsync( - string androidSdkPath, - string javaSdkPath, - string cmdLineToolsPath, - IEnumerable licenses, - CancellationToken token, - string logPath = null, - bool throwsErrorIfValidationFailed = false) - { - return Task.Run(async () => - { - var progress = new AggregateProgressSink(logPath); - - try - { - var error = ValidateAcceptLicensesArguments(androidSdkPath, javaSdkPath, cmdLineToolsPath, licenses, progress); - if (!string.IsNullOrEmpty(error)) - { - if (throwsErrorIfValidationFailed) - { - throw new NotSupportedException(error); - } - else - { - return; - } - } - - var licenseIDs = licenses.Select(x => x.ID).Distinct(); - progress.Report($"Licenses to be accepted: {string.Join("|", licenseIDs)}"); - - // run sdkmanager from cmdline-tools to accept the licenses - await WriteGoogleLicensesAsync(androidSdkPath, javaSdkPath, cmdLineToolsPath, licenses, token, progress); - - // it is required because the hash can be different than the generated by google - // Xamarin feed licenses text can be not in sync with latest google feed licenses text - // Xamarin feed is generated/updated on each VS release, - // and VS releases are not in sync with the cadence of updates of Google feed - WriteVSLicenses(androidSdkPath, licenses, token, progress); - } - finally - { - progress.Dispose(); - } - }, token); - } - - string ValidateAcceptLicensesArguments( - string androidSdkPath, - string javaSdkPath, - string cmdLineToolsPath, - IEnumerable licenses, - AggregateProgressSink progress) - { - if (!licenses.Any()) - { - progress?.Report("Android licenses acceptance discarded, no licenses to accept"); - return string.Empty; - } - - if (string.IsNullOrEmpty(androidSdkPath) || !Directory.Exists(androidSdkPath)) - { - progress?.Report(Resources.AccepLicensesFailedAndroidSDKNotFound); - return Resources.AccepLicensesFailedAndroidSDKNotFound; - } - - if (string.IsNullOrEmpty(javaSdkPath) || !Directory.Exists(javaSdkPath)) - { - progress?.Report(Resources.AccepLicensesFailedJavaSDKNotFound); - return Resources.AccepLicensesFailedJavaSDKNotFound; - } - - if (string.IsNullOrEmpty(cmdLineToolsPath)) - { - progress?.Report(Resources.AccepLicensesFailedCMDLineToolsNotFound); - return Resources.AccepLicensesFailedCMDLineToolsNotFound; - } - - var cmdLineToolsPropertiesFilePath = Path.Combine(cmdLineToolsPath, "source.properties"); - if (!File.Exists(cmdLineToolsPropertiesFilePath)) - { - progress?.Report(Resources.AccepLicensesFailedCMDLineToolsNotFound); - return Resources.AccepLicensesFailedCMDLineToolsNotFound; - } - - return string.Empty; - } - - protected void WriteVSLicenses( - string androidSdkPath, - IEnumerable licenses, - CancellationToken token, - AggregateProgressSink progress) - { - if (!licenses.Any()) - return; - - // creates local licenses storage folder - if (token.IsCancellationRequested) - return; - - progress.Report("Running local accept licenses process"); - - try - { - var licensesPath = GetLicensesPath(androidSdkPath); - if (!Directory.Exists(licensesPath)) - Directory.CreateDirectory(licensesPath); - - // save licenses - var licensesToAccept = licenses.Where(license => !string.IsNullOrEmpty(license.ID)).GroupBy(license => license); - foreach (var l in licensesToAccept) - { - if (token.IsCancellationRequested) - return; - - var androidLicense = l.Key; - - var licensePath = Path.Combine(licensesPath, androidLicense.ID); - var licenseHash = GetLicenseHash(androidLicense); - - WriteLicenseHash(licensePath, licenseHash); - } - - progress.Report("Running local accept licenses process completed"); - } - catch (Exception ex) - { - progress.Report($"Running local accept licenses process failed: {ex.Message}"); - } - } - - protected virtual void WriteLicenseHash(string licensePath, string licenseHash) - { - // same format as generated by google sdkmanager licenses command - var sb = new StringWriter(); - - if (File.Exists(licensePath)) - { - sb.WriteLine(""); // enter for previous line - } - - sb.WriteLine(""); // force empty line - sb.WriteLine(licenseHash); // hash - - File.AppendAllText(licensePath, sb.ToString()); - } - - protected async Task WriteGoogleLicensesAsync( - string androidSdkPath, - string javaSdkPath, - string cmdLineToolsPath, - IEnumerable licenses, - CancellationToken token, - AggregateProgressSink progress) - { - progress.Report("Running sdkmanager --licenses --verbose"); - - var standardOutput = progress.ForOutputs; - var standardError = progress.ForErrors; - - var sdkManagerApp = string.Empty; - switch (AndroidSDKContext.Instance.Platform) - { - case AndroidSDKPlatform.Linux: - case AndroidSDKPlatform.Mac: - sdkManagerApp = "sdkmanager"; - break; - case AndroidSDKPlatform.Windows: - sdkManagerApp = "sdkmanager.bat"; - break; - - default: - throw new InvalidOperationException("Unsupported platform"); - } - - var processStartInfo = new ProcessStartInfo(fileName: Path.Combine(cmdLineToolsPath, "bin", sdkManagerApp), "--licenses --verbose"); - processStartInfo.WorkingDirectory = Path.Combine(cmdLineToolsPath, "bin"); - processStartInfo.WindowStyle = ProcessWindowStyle.Hidden; - processStartInfo.UseShellExecute = false; - processStartInfo.RedirectStandardError = true; - processStartInfo.RedirectStandardInput = true; - processStartInfo.RedirectStandardOutput = true; - processStartInfo.CreateNoWindow = true; - - if (!string.IsNullOrEmpty(javaSdkPath)) - { - // Use short path (8.3 format) for JAVA_HOME on Windows to avoid batch script parsing issues - // when paths contain parentheses like "Program Files (x86)" which break CMD.exe IF/FOR blocks. - // See: https://dev.azure.com/devdiv/DevDiv/_workitems/edit/2632833 - var javaHomePath = AndroidSDKContext.Instance.Platform == AndroidSDKPlatform.Windows - ? CommonUtilities.GetShortPath(javaSdkPath) - : javaSdkPath; - processStartInfo.EnvironmentVariables["JAVA_HOME"] = javaHomePath; - } - - var process = new Process(); - process.StartInfo = processStartInfo; - - bool matchLicenseId = false; - var loadingLocalRepository = true; - - var inputAnswers = new ConcurrentQueue(); - inputAnswers.Enqueue("Y"); // to accept the review "Review licenses that have not been accepted (y/N)?" - - if (processStartInfo.RedirectStandardOutput) - { - process.OutputDataReceived += (sender, e) => - { - if (e.Data != null) - { - standardOutput?.Report(e.Data); - - if (e.Data.Contains("(y/N)?")) - { - // when the message "Review licenses that have not been accepted (y/N)?" is reported the loading phase and display all licenses text ends - loadingLocalRepository = false; - } - - // try to match the license id from message: "License {id}:" - if (loadingLocalRepository && licenses.Any(x => e.Data.Contains($"{x.ID}:"))) - { - matchLicenseId = true; - } - - if (loadingLocalRepository && e.Data.Trim().Equals("Accepted")) - { - // reset the match when an accepted license is detected - matchLicenseId = false; - } - - if (loadingLocalRepository && e.Data.Trim().Contains("Not yet accepted")) - { - // enqueue a Y/N answer - if (matchLicenseId) - { - matchLicenseId = false; - inputAnswers.Enqueue("Y"); - } - else - { - inputAnswers.Enqueue("N"); - } - } - } - }; - } - - if (processStartInfo.RedirectStandardError) - { - process.ErrorDataReceived += (sender, e) => - { - standardError?.Report(e.Data); - }; - } - - process.Start(); - - if (processStartInfo.RedirectStandardOutput) - process.BeginOutputReadLine(); - - if (processStartInfo.RedirectStandardError) - process.BeginErrorReadLine(); - - process.StandardInput.AutoFlush = true; - - while (!process.HasExited) - { - if (token.IsCancellationRequested) - { - process.Kill(); - } - else - { - try - { - if (inputAnswers.Any() && inputAnswers.TryDequeue(out var inputAnswer)) - { - await process.StandardInput.WriteLineAsync(inputAnswer); - } - } - catch (Exception e) - { - progress.Report(e.Message); - } - } - } - - if (!token.IsCancellationRequested && process.ExitCode > 0) - { - var errorMessage = $""" - {Resources.GoogleAccepLicensesFailed}. - Exit code: {process.ExitCode}. - Android SDK: '{androidSdkPath}'. - Java SDK: '{javaSdkPath}'. - Command-line tools: '{cmdLineToolsPath}'. - """; - - if (!string.IsNullOrEmpty(standardError.Errors)) - { - errorMessage += $" Errors: {standardError.Errors}"; - } - - progress.Report(errorMessage); - throw new Exception(errorMessage); - } - } - - protected class AggregateProgressSink : IProgress, IDisposable - { - private StreamWriter writer; - - public AggregateProgressSink(string logPath) - { - this.ForOutputs = new OutputProgressSink(this); - this.ForErrors = new ErrorProgressSink(this); - this.writer = string.IsNullOrEmpty(logPath) ? null : new StreamWriter(logPath); - } - - public OutputProgressSink ForOutputs { get; private set; } - - public ErrorProgressSink ForErrors { get; private set; } - - public void Report(string value) - { - this.writer?.WriteLine(value); - } - - public void Dispose() - { - this.writer?.Close(); - this.writer = null; - } - } - - protected class OutputProgressSink : IProgress - { - private IProgress fileSink; - - public OutputProgressSink(IProgress fileSink) - { - this.fileSink = fileSink; - } - - public void Report(string value) - { - this.fileSink.Report(value); - } - } - - protected class ErrorProgressSink : IProgress - { - private readonly StringBuilder allErrors = new StringBuilder(); - private readonly IProgress fileSink; - - public ErrorProgressSink(IProgress fileSink) - { - this.fileSink = fileSink; - } - - public string Errors => this.allErrors.ToString(); - - public void Report(string value) - { - this.fileSink.Report(value); - this.allErrors.AppendLine(value); - } - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Archive.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Archive.cs deleted file mode 100644 index 00bdd36914e..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Archive.cs +++ /dev/null @@ -1,276 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; - -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Describes a single package archive - /// - public class Archive : ArchiveBase, IEquatable - { - /// - /// Gets the collection of patches for this archive. This library currently does not support applying these - /// patches, instead it always downloads the full archive from the specified URL - /// - /// The list of patches (if any) - public IList Patches { get; set; } - - /// - /// Gets a value indicating whether this was downloaded. - /// true will be returned only if is set and refers to an existing file. - /// Checksum is not verified when reading this property. - /// - /// true if archive was downloaded; otherwise, false. - public bool WasDownloaded => !String.IsNullOrEmpty(GetDownloadPath(false)); - - /// - /// Gets or sets the downloaded file path. The installer assembly resets this property to null when returning archive - /// instance from but otherwise it is responsibilty of the client code - /// to set the property to a valid path of a downloaded archive. - /// - /// The downloaded file path. - public string DownloadedFilePath { get; set; } - - /// - /// Gets the Android component that owns this Archive, if any - /// - /// The owner component. - public IAndroidComponent Owner { get; internal set; } - - /// - /// Initializes a new instance of the class. - /// - /// The host operating system. - public Archive(string hostOS) : base(hostOS) - { - } - - /// - /// Verifies whether the downloaded archive is indeed found on disk and whether it passes checksum verification - /// (if is true). - /// - /// true, if downloaded archive is valid, false otherwise. - /// If set to true verify the archive checksum. - public bool IsDownloadValid(bool verifyChecksum = true) - { - string filePath = GetDownloadPath(); - if (String.IsNullOrEmpty(filePath)) - return false; - - if (!verifyChecksum) - return true; - - if (!VerifyChecksum(filePath, ChecksumType, Checksum, Url)) - { - Logger.Warning($"Downloaded file '{DownloadedFilePath}' fails checksum verification for Android SDK archive '{Url}'"); - return false; - } - - return true; - } - - /// - /// Verifies against using the algorithm - /// named by . The algorithm string is normalized (trimmed, - /// lowercased, with a single hyphen stripped) so values such as "sha-1" / "SHA1" / "sha-256" - /// are all accepted. A null or empty algorithm defaults to SHA-1 to match the historical - /// manifest behavior. Unknown algorithms or hash-length mismatches log a warning and return - /// false rather than silently falling back. - /// - internal static bool VerifyChecksum(string filePath, string algorithm, string hash, Uri url) - { - string normalized = (algorithm ?? string.Empty).Trim().ToLowerInvariant().Replace("-", string.Empty); - string trimmedHash = hash?.Trim(); - - if (string.IsNullOrEmpty(normalized) || normalized == "sha1") - { - if (!string.IsNullOrEmpty(trimmedHash) && trimmedHash.Length != 40) - { - Logger.Warning($"Checksum for Android SDK archive '{url}' is declared as SHA-1 but its length ({trimmedHash.Length}) is not 40 hex characters"); - return false; - } - return CheckSHA1(filePath, trimmedHash); - } - - if (normalized == "sha256") - { - if (!string.IsNullOrEmpty(trimmedHash) && trimmedHash.Length != 64) - { - Logger.Warning($"Checksum for Android SDK archive '{url}' is declared as SHA-256 but its length ({trimmedHash.Length}) is not 64 hex characters"); - return false; - } - return CheckSHA256(filePath, trimmedHash); - } - - Logger.Warning($"Unknown checksum algorithm '{algorithm}' declared for Android SDK archive '{url}'; refusing to verify"); - return false; - } - - /// - /// Checks whether the downloaded archive is valid (verifying the checksum if is true) and - /// whether it can be installed on the current system. - /// - /// true, if the archive is installable on the current system, false otherwise. - /// If set to true verify checksum. - /// If set to true verify archive host os. - public bool IsInstallable(bool verifyChecksum = true, bool checkPlatform = true) - { - return (!checkPlatform || IsValidForSystem()) && IsDownloadValid(verifyChecksum); - } - - /// - /// Checks whether archive's platform and host-arch are matching the current system. - /// - /// - public override bool IsValidForSystem() - { - if (!IsPlatformValid()) - return false; - - if (IsHostArchValid()) - return true; - - // custom logic: windows emulator only have x64 archives - return Platform == AndroidSDKPlatform.Windows && - (string.IsNullOrEmpty(Owner?.FileSystemPath) || (Owner.FileSystemPath.StartsWith("emulator") && HostArch.StartsWith("x"))); - } - - string GetDownloadPath(bool logMissing = true) - { - string filePath = DownloadedFilePath?.Trim(); - if (String.IsNullOrEmpty(filePath)) - return null; - - if (!File.Exists(filePath)) - { - if (logMissing) - Logger.Info($"Downloaded file '{DownloadedFilePath}' not found for Android SDK archive '{Url}'"); - return null; - } - - return filePath; - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA5350:Do Not Use Weak Cryptographic Algorithms", Justification = "Used to verify checksums provided by an external party.")] - static bool CheckSHA1(string filePath, string sha1hash) - { - sha1hash = sha1hash?.Trim(); - if (String.IsNullOrEmpty(sha1hash) || sha1hash.Length != 40) - return false; - - using (var sha1 = SHA1.Create())// CodeQL [SM02196] Receiving external information: Used to verify checksums provided by an external party - { - using (var fs = File.OpenRead(filePath)) - { - byte[] hash = sha1.ComputeHash(fs); - string shash = BitConverter.ToString(hash).Replace("-", ""); - return string.Equals(shash, sha1hash, StringComparison.OrdinalIgnoreCase); - } - } - } - - static bool CheckSHA256(string filePath, string sha256hash) - { - sha256hash = sha256hash?.Trim(); - if (String.IsNullOrEmpty(sha256hash) || sha256hash.Length != 64) - return false; - - using (var sha256 = SHA256.Create()) - { - using (var fs = File.OpenRead(filePath)) - { - byte[] hash = sha256.ComputeHash(fs); - string shash = BitConverter.ToString(hash).Replace("-", ""); - return string.Equals(shash, sha256hash, StringComparison.OrdinalIgnoreCase); - } - } - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public bool Equals(Archive other) - { - if (!base.Equals(other)) - return false; - - if (Patches == null) - { - if (other.Patches != null) - return false; - } - else - { - if (other.Patches == null) - return false; - if (!ComparePatches(other.Patches)) - return false; - } - - return true; - } - - bool ComparePatches(IList otherPatches) - { - if (Patches.Count != otherPatches.Count) - return false; - - for (int i = 0; i < otherPatches.Count; i++) - { - ArchivePatch localPatch = Patches[i]; - ArchivePatch otherPatch = otherPatches[i]; - - if (localPatch == null) - { - if (otherPatch != null) - return false; - continue; - } - - if (otherPatch == null) - return false; - - if (!localPatch.Equals(otherPatch)) - return false; - } - - return true; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals(Object obj) - { - return Equals(obj as Archive); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode() - { - int hashCode = base.GetHashCode(); - return hashCode.XorWith(Patches?.GetHashCode()); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ArchiveBase.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ArchiveBase.cs deleted file mode 100644 index 5ace55a68f3..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ArchiveBase.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Describes a single package archive - /// - public abstract class ArchiveBase : IArchive - { - public ArchiveBase(string hostOS) - { - HostOS = hostOS; - Platform = AndroidUtilities.GetPlatformFromOS(hostOS); - } - - /// - /// Gets the archive size - /// - /// Archive size - public ulong Size { get; set; } - - /// - /// Gets the checksum of the archive. The algorithm is identified by ; - /// when is null or empty the checksum is assumed to be SHA-1. - /// - /// Checksum digest as a hex string - public string Checksum { get; set; } - - /// - /// Gets the checksum algorithm declared by the manifest for , - /// for example sha1 or sha256. A null or empty value means SHA-1 (the historical default). - /// - /// Checksum algorithm name - public string ChecksumType { get; set; } - - /// - /// Gets the archive URL - /// - /// Archive URL - public Uri Url { get; set; } - - /// - /// Gets the target (host) operating system of the archive (if any) - /// - /// Host operating system - public string HostOS { get; } - - /// - /// Mapping of into one of the enumeration members - /// - /// Archive platform. - public AndroidSDKPlatform Platform { get; } - - /// - /// Native word size of the host operating system. - /// - /// Host operating system word size - public uint HostBits { get; set; } - - /// - /// CPU Architecture of the host operating system. - /// - /// Host operating CPU architecture - public string HostArch { get; set; } - - /// - /// Checks whether archive's platform and host-arch are matching the current system. - /// - /// - public abstract bool IsValidForSystem(); - - /// - /// Checks whether archive's platform is matching the current system. - /// - /// - public virtual bool IsPlatformValid() - { - return (Platform == AndroidSDKPlatform.Any || Platform == AndroidSDKContext.Instance.Platform); - } - - /// - /// Checks whether archive's host-arch is matching the current system. - /// - /// - public virtual bool IsHostArchValid() - { - return string.IsNullOrEmpty(HostArch) || HostArch == AndroidSDKContext.Instance.HostArch; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public bool Equals(IArchive other) - { - if (other == null) - return false; - - if (ReferenceEquals(this, other)) - return true; - - if (!string.Equals(Checksum, other.Checksum, StringComparison.Ordinal)) - return false; - - if (HostBits != other.HostBits) - return false; - - if (!string.Equals(HostOS, other.HostOS, StringComparison.Ordinal)) - return false; - - if (Size != other.Size) - return false; - - if (Url != other.Url) - return false; - - return true; - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode() - { - int hashCode = base.GetHashCode(); - hashCode = hashCode.XorWith(HostBits.GetHashCode()); - hashCode = hashCode.XorWith(HostOS?.GetHashCode()); - hashCode = hashCode.XorWith(Size.GetHashCode()); - return hashCode.XorWith(Url?.GetHashCode()); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ArchivePatch.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ArchivePatch.cs deleted file mode 100644 index ae1324e37d9..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ArchivePatch.cs +++ /dev/null @@ -1,112 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Represents a single archive patch instance. - /// - public sealed class ArchivePatch : IEquatable - { - /// - /// Gets the revision of the parent archive this patch must be applied to. - /// - /// Base archive revision - public AndroidRevision BasedOn { get; internal set; } - - /// - /// Gets the patch download size - /// - /// The size. - public ulong Size { get; internal set; } - - /// - /// Gets the checksum of the patch. The algorithm is identified by ; - /// when is null or empty the checksum is assumed to be SHA-1. - /// - /// Checksum digest as a hex string - public string Checksum { get; internal set; } - - /// - /// Gets the checksum algorithm declared by the manifest for , - /// for example sha1 or sha256. A null or empty value means SHA-1. - /// - /// Checksum algorithm name - public string ChecksumType { get; internal set; } - - /// - /// Gets the patch URL - /// - /// Archive URL - public Uri Url { get; internal set; } - - internal ArchivePatch () - { - } - - /// - /// Determines whether the specified is equal to the - /// current . - /// - /// The to compare with the current . - /// true if the specified is equal to the - /// current ; otherwise, false. - public bool Equals (ArchivePatch other) - { - if (other == null) - return false; - - if (ReferenceEquals (this, other)) - return true; - - if (Size != other.Size) - return false; - - if (Url != other.Url) - return false; - - if (!string.Equals (Checksum, other.Checksum, StringComparison.Ordinal)) - return false; - - if (BasedOn == null) { - if (other.BasedOn != null) - return false; - } else if (BasedOn != other.BasedOn) - return false; - - return true; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as ArchivePatch); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - hashCode = hashCode.XorWith (Size.GetHashCode ()); - hashCode = hashCode.XorWith (Url?.GetHashCode ()); - hashCode = hashCode.XorWith (Checksum?.GetHashCode ()); - return hashCode.XorWith (BasedOn?.GetHashCode ()); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/BasePackage.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/BasePackage.cs deleted file mode 100644 index 6cd008f8ebc..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/BasePackage.cs +++ /dev/null @@ -1,911 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2018, Microsoft Corp. (https://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Xml; -using System.Xml.Linq; -using Xamarin.Installer.Common; -using IOPath = System.IO.Path; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - public abstract class BasePackage : IEquatable, IAndroidComponent, IAndroidComponentInternal - { - protected Repository Repository { get; } - protected IList OriginalArchives { get; } - - public event EventHandler StatusChanged; - - public abstract AndroidComponentType ComponentType { get; } - public Guid UniqueID { get; } = Guid.NewGuid(); - public bool IsEssential { get; set; } - public bool IgnoreFailure { get; set; } - public bool Present { get; set; } - public bool NeedsUpdate { get; set; } - public string Path { get; set; } - public string FileSystemPath { get; set; } - public bool Obsolete { get; set; } - public bool Preview => GetPreview(); - public AndroidComponentInfo Info { get; set; } - public AndroidRevision Revision { get; set; } - public AndroidRevision InstalledRevision { get; set; } - public string DisplayName { get; set; } - public string DetailedDescription => GetDetailedDescription(); - public IList Dependencies { get; set; } - public abstract Channel Channel { get; } - public IList Archives { get; protected set; } - public License License => Repository.GetLicense(LicenseID); - public string LicenseID { get; set; } - public Uri ManifestURL { get; } - public IXmlLineInfo Location { get; } - public bool ForceInstallation { get; set; } - - public BasePackage(Repository repository, Uri manifestURL, IXmlLineInfo location, IList archives) - { - Repository = repository ?? throw new ArgumentNullException(nameof(repository)); - ManifestURL = manifestURL ?? throw new ArgumentNullException(nameof(manifestURL)); - Location = location; - OriginalArchives = archives; - if (archives == null || archives.Count == 0) - return; - - foreach (Archive archive in archives) - { - if (archive == null) - continue; - archive.Owner = this; - } - } - - public IEnumerable SupportedPlatforms - { - get - { - //todo OriginalArchives? - foreach (var archive in Archives) - yield return archive.Platform; - } - } - - public bool IsPlatformSpecific - { - get - { - return !Archives.Any(a => a.Platform == AndroidSDKPlatform.Any || a.Platform == AndroidSDKPlatform.Unknown); - } - } - - /// - /// NOTE: Using in ManifestGenerator only. - /// - /// - public void ExcludePlatform(AndroidSDKPlatform platform) - { - Archives = Archives.Where(a => a.Platform != platform).ToList(); - Dependencies = Dependencies.Where(d => d.Platform != platform).ToList(); - } - - protected void PopulatePlatformArchives(bool includeAllArchives) - { - var alist = new List(); - AndroidSDKPlatform platform = AndroidSDKContext.Instance.Platform; - - foreach (Archive archive in OriginalArchives) - { - if (archive == null || (!includeAllArchives && !archive.IsValidForSystem())) - continue; - alist.Add(archive); - } - - - bool IsBitsValid(uint bits) => ((bits == 64) == CommonUtilities.Helpers.Is64BitOS); - // Remove all archives with HostBits not matching the OS Bits - // Apply only if there is any matching in the list - if (!includeAllArchives && alist.Count > 1 && alist.Any(a => IsBitsValid(a.HostBits))) - { - alist.RemoveAll(a => !IsBitsValid(a.HostBits)); - } - - Archives = alist.AsReadOnly(); - } - - protected virtual string GetDetailedDescription() - { - string desc = $"{DisplayName} r{Revision}"; - if (!String.IsNullOrEmpty(Info?.DetailedDescription)) - return $"{desc} [{Info?.DetailedDescription}]"; - return desc; - } - - protected void OnStatusChange(AndroidComponentStatus status) - { - if (StatusChanged == null) - return; - - StatusChanged(this, new AndroidComponentStatusChangeEventArgs(status, this)); - } - - public void Remove(string androidSDKRoot) - { - OnStatusChange(AndroidComponentStatus.RemovalStarted); - try - { - PackageMetadata metadata = CreateMetadata(this); - - DoRemove(androidSDKRoot, retries: 5, delayInSeconds: 5); - - PerformDetection(androidSDKRoot, true); - RefreshMetadata(this, false); - } - finally - { - OnStatusChange(AndroidComponentStatus.RemovalEnded); - } - } - - void DoRemove(string androidSDKRoot, int retries, int delayInSeconds) - { - if (String.IsNullOrEmpty(androidSDKRoot)) - throw new ArgumentException("must not be null or empty", nameof(androidSDKRoot)); - - var ex = default(Exception); - var success = false; - while (!success && retries > 0) - { - try - { - DoRemove(androidSDKRoot); - success = true; - } - catch (UnauthorizedAccessException uae) - { - ex = uae; - retries = retries - 1; - Thread.Sleep(TimeSpan.FromSeconds(delayInSeconds)); - delayInSeconds = delayInSeconds + 3; - } - } - - if (!success && ex != null) - throw ex; - } - - void DoRemove(string androidSDKRoot) - { - if (String.IsNullOrEmpty(androidSDKRoot)) - throw new ArgumentException("must not be null or empty", nameof(androidSDKRoot)); - - string packagePath = IOPath.Combine(androidSDKRoot, FileSystemPath); - if (File.Exists(packagePath)) - File.Delete(packagePath); - else if (Directory.Exists(packagePath)) - Directory.Delete(packagePath, true); - else - return; - - DeleteDirTreeIfEmpty( - new DirectoryInfo(GetRealDirectoryName(androidSDKRoot)), - new DirectoryInfo(GetRealDirectoryName(IOPath.GetDirectoryName(packagePath))) - ); - } - - public abstract void RefreshMetadata(IAndroidComponent component, bool ignoreInstalledState = true); - protected abstract PackageMetadata CreateMetadata(BasePackage component); - - public void PerformDetection(string androidSDKRoot, bool isRefresh = false) - { - if (String.IsNullOrEmpty(androidSDKRoot)) - throw new ArgumentException("must not be null or empty", nameof(androidSDKRoot)); - - PackageMetadata metadata = isRefresh ? CreateMetadata(this) : null; - string description = DetailedDescription; - Present = false; - InstalledRevision = null; - ForceInstallation = false; - OnStatusChange(AndroidComponentStatus.DetectionStarted); - try - { - NeedsUpdate = Detect(androidSDKRoot, description); - } - catch (Exception ex) - { - LogInfo($"Component {description} detection failed with exception. Component will be marked as outdated."); - LogInfo(ex.ToString()); - NeedsUpdate = true; - } - finally - { - OnStatusChange(AndroidComponentStatus.DetectionEnded); - if (MetadataChanged(metadata)) - OnStatusChange(AndroidComponentStatus.MetadataUpdated); - } - } - - // Returns `true` if the package is absent or is older than our version - bool Detect(string androidSDKRoot, string description) - { - Present = false; - string fullPath = IOPath.Combine(androidSDKRoot, FileSystemPath); - if (!Directory.Exists(fullPath)) - { - LogDebug($"Component {description} not present on the system"); - return true; - } - LogDebug($"Detecting component {description} in directory '{fullPath}'"); - - // Treat the package as present only if we have any file with version information - AndroidRevision instv = null; - string manifestFile = IOPath.Combine(fullPath, "package.xml"); - if (File.Exists(manifestFile)) - { - Present = true; - instv = GetPackageRevision(manifestFile); - } - - if (instv == null) - { - manifestFile = IOPath.Combine(fullPath, "source.properties"); - if (File.Exists(manifestFile)) - { - Present = true; - var props = AndroidUtilities.ReadAndroidProperties(manifestFile); - string rev; - props.GetPkgRevision(out rev, out instv, DisplayName); - } - } - - // https://bugzilla.xamarin.com/show_bug.cgi?id=59714 AndroidComponentInfoSystemImage.Abi reads Default for a x86 image - // Try to fix system image' package.xml -> abi as it might be wrong - if (ComponentType == AndroidComponentType.SystemImage && Present) - { - AndroidComponentInfoSystemImage info = (AndroidComponentInfoSystemImage)Info; - if (info != null - && (info.Abi == AndroidSystemImageAbi.X86 - || info.Abi == AndroidSystemImageAbi.ARMV7a - || info.Abi == AndroidSystemImageAbi.ARM64V8a)) - { - manifestFile = IOPath.Combine(fullPath, "package.xml"); - if (File.Exists(manifestFile)) - { - string abi = GetAbi(manifestFile); - - // Rewrite the entire manifest if the abi value differs - if (abi != null && abi != info.GetAbiManifestString()) - { - LogWarning($"Found invalid abi \"{abi}\" (expected value: \"{info.GetAbiManifestString()}\") in \"{manifestFile}\", regenerating package.xml..."); - try - { - GeneratePackageXml(manifestFile); - } - catch (Exception ex) - { - if (ex is IOException || ex is UnauthorizedAccessException) - { - LogError($"Could not regenerate package.xml for \"{manifestFile}\" as the process might not have administrative privileges. You will need to fix the manifest manually.\nHere is the error details: {ex}"); - // Marking component as not installed - Present = false; - InstalledRevision = null; - return true; - } - throw; - } - } - } - } - } - - if (instv == null) - { - LogInfo($" Version information not found for component {description}"); - return true; - } - - LogDebug($" Found revision {instv} on the system"); - InstalledRevision = instv; - - return Revision > InstalledRevision; - } - - protected AndroidRevision GetPackageRevision(string manifestFile) - { - try - { - XDocument doc = XDocument.Load(manifestFile); - XElement revision = doc.Descendants("revision")?.FirstOrDefault(); - if (revision == null) - return null; - - // We should use RevisionParser but due to its requirements (parser context) it's rather - // unwieldy, hence the code duplication here - return new AndroidRevision( - ParseAsInt(revision.Element("major")), - ParseAsInt(revision.Element("minor")), - ParseAsInt(revision.Element("micro")), - ParseAsInt(revision.Element("preview")) - ); - } - catch (Exception ex) - { - LogDebug($"Exception caught trying to parse {manifestFile} for package version information."); - LogDebug(ex.ToString()); - return null; - } - } - - protected string GetAbi(string manifestFile) - { - try - { - XDocument doc = XDocument.Load(manifestFile); - XElement abi = doc.Descendants("abi")?.FirstOrDefault(); - if (abi == null) - return null; - - return abi.Value; - } - catch (Exception ex) - { - LogDebug($"Exception caught trying to parse {manifestFile} for abi information."); - LogDebug(ex.ToString()); - return null; - } - } - - protected int ParseAsInt(XElement e) - { - string v = e?.Value?.Trim(); - if (String.IsNullOrEmpty(v)) - return -1; - - int ret; - if (!Int32.TryParse(v, out ret)) - return -1; - - return ret; - } - - protected string GetRealDirectoryName(string path) - { - if (!Directory.Exists(path)) - return path; - - string cwd = Environment.CurrentDirectory; - try - { - Directory.SetCurrentDirectory(path); - return Environment.CurrentDirectory; - } - finally - { - Directory.SetCurrentDirectory(cwd); - } - } - - protected void DeleteDirTreeIfEmpty(DirectoryInfo stopAt, DirectoryInfo di) - { - if (string.Equals(stopAt.FullName, di.FullName, StringComparison.Ordinal)) - return; - - if (di.EnumerateFileSystemInfos().Any()) - return; - - DirectoryInfo parent = di.Parent; - di.Delete(); - DeleteDirTreeIfEmpty(stopAt, parent); - } - - protected virtual bool MetadataChanged(PackageMetadata metadata, bool update = false, bool ignoreInstalledState = false) - { - if (metadata == null) - return false; - - bool haveChanges = false; - if (!metadata.Archives.AreEqual(Archives)) - { - if (update) - { - Archives = new List(metadata.Archives).AsReadOnly(); - haveChanges = true; - } - else - return true; - } - - if (!metadata.Dependencies.AreEqual(Dependencies)) - { - if (update) - { - Dependencies = metadata.Dependencies != null ? new List(metadata.Dependencies).AsReadOnly() : null; - haveChanges = true; - } - else - return true; - } - - if (!string.Equals(metadata.DisplayName, DisplayName, StringComparison.Ordinal)) - { - if (update) - { - DisplayName = metadata.DisplayName; - haveChanges = true; - } - else - return true; - } - - if (!string.Equals(metadata.FileSystemPath, FileSystemPath, StringComparison.Ordinal)) - { - if (update) - { - FileSystemPath = metadata.FileSystemPath; - haveChanges = true; - } - else - return true; - } - - if (!AreInfosEqual(Info, metadata.Info)) - { - if (update) - { - Info = metadata.Info; - haveChanges = true; - } - else - return true; - } - - if (!ignoreInstalledState && metadata.InstalledRevision != InstalledRevision) - { - if (update) - { - InstalledRevision = metadata.InstalledRevision; - haveChanges = true; - } - else - return true; - } - - if (!ignoreInstalledState && metadata.NeedsUpdate != NeedsUpdate) - { - if (update) - { - NeedsUpdate = metadata.NeedsUpdate; - haveChanges = true; - } - else - return true; - } - - if (metadata.Obsolete != Obsolete) - { - if (update) - { - Obsolete = Obsolete; - haveChanges = true; - } - else - return true; - } - - if (!string.Equals(metadata.Path, Path, StringComparison.OrdinalIgnoreCase)) - { - if (update) - { - Path = metadata.Path; - haveChanges = true; - } - else - return true; - } - - if (!ignoreInstalledState && metadata.Present != Present) - { - if (update) - { - Present = metadata.Present; - haveChanges = true; - } - else - return true; - } - - if (metadata.Revision != Revision) - { - if (update) - { - Revision = metadata.Revision; - haveChanges = true; - } - else - return true; - } - - return haveChanges; - } - - public void Install(string archivePath, string androidSDKRoot, - InstallationProgressEventArgs.InstallationProgressActionDelegate progressCallback = null) - { - OnStatusChange(AndroidComponentStatus.InstallationStarted); - try - { - DoInstall(archivePath, androidSDKRoot, progressCallback); - } - finally - { - OnStatusChange(AndroidComponentStatus.InstallationEnded); - } - } - - void DoInstall(string archivePath, string androidSDKRoot, - InstallationProgressEventArgs.InstallationProgressActionDelegate progressCallback = null) - { - if (String.IsNullOrEmpty(archivePath)) - throw new ArgumentException("must not be null or empty", nameof(archivePath)); - if (String.IsNullOrEmpty(androidSDKRoot)) - throw new ArgumentException("must not be null or empty", nameof(androidSDKRoot)); - - string targetDirectory = IOPath.Combine(androidSDKRoot, FileSystemPath); - OnStatusChange(AndroidComponentStatus.UnpackingStarted); - - bool success = false; - try - { - success = InstallArchive(DetailedDescription, archivePath, targetDirectory, progressCallback); - } - catch (Exception ex) - { - LogError($"Archive '{archivePath}' installation failed with error: {ex}"); - throw; - } - finally - { - OnStatusChange(AndroidComponentStatus.UnpackingEnded); - } - - if (success) - GeneratePackageXml(IOPath.Combine(targetDirectory, "package.xml")); - else - throw new InvalidOperationException("Archive installation failed."); - } - - bool InstallArchive(string description, string archivePath, string targetDirectory, - InstallationProgressEventArgs.InstallationProgressActionDelegate progressCallback = null) - { - //return false; // this is a test - //throw new Exception("A test InstallArchive exception."); - var rnd = new Random(); - string componentUnzippedPath; - - int moveSplitPercents = DirectorySizeMonitoringTimer.CalculateMoveProgressSplit(archivePath); - int unzipSplitPercents = 100 - moveSplitPercents; - - // LogDebug ($"unzipSplitPercents: {unzipSplitPercents} | moveSplitPercents: {moveSplitPercents}"); - - // A small race here but I think we can accept the risks :) - string temporaryPath = IOPath.Combine(IOPath.GetTempPath(), IOPath.GetRandomFileName()); - try - { - componentUnzippedPath = CommonUtilities.Helpers.Unzip(temporaryPath, archivePath, AndroidSDKContext.Instance.UserName, (progress) => - { - try - { - progressCallback?.Invoke((float)DirectorySizeMonitoringTimer.Remap(progress, 0, 100, 0, unzipSplitPercents)); - } - catch (Exception ex) - { - Logger.Error($"[InstallArchive] progress callback exception: {ex}"); - } - }).RemoveTrailingDirectorySeparator(); - } - catch (Exception ex) - { - LogError($"Exception caught while unzipping '{archivePath}' in '{temporaryPath}'. {ex}"); - throw; - } - - LogDebug($"Android component '{description}' unpacked in directory '{componentUnzippedPath}'"); - LogDebug($"Android component destination path: {targetDirectory}"); - string oldDestinationPath = null; - - if (Directory.Exists(targetDirectory)) - { - oldDestinationPath = targetDirectory + ".old" + rnd.Next(Int32.MaxValue); - LogInfo($"Moving old directory '{targetDirectory}' to '{oldDestinationPath}'"); - - // We'll be on the same filesystem/volume, so we can just use this instead of recursive copy+delete - Directory.Move(targetDirectory, oldDestinationPath); - } - - bool ret = true; - Exception exMoveDirectory = null; - try - { - int idx = targetDirectory.LastIndexOf(IOPath.DirectorySeparatorChar); - string leadingPath; - if (idx > 1) - leadingPath = targetDirectory.Substring(0, idx); - else - leadingPath = targetDirectory; - - if (!Directory.Exists(leadingPath)) - { - LogInfo($"Creating Android component's parent path '{leadingPath}'"); - Directory.CreateDirectory(leadingPath); - } - LogInfo("Moving Android component to its destination path."); - - using (var monitoringTimer = new DirectorySizeMonitoringTimer(targetDirectory, componentUnzippedPath, (progress) => - { - try - { - progressCallback?.Invoke(progress); - } - catch (Exception ex) - { - Logger.Error($"[InstallArchive] progress callback exception: {ex}"); - } - }, remapFrom: unzipSplitPercents, remapTo: 100f)) - { - CommonUtilities.MoveDirectory(componentUnzippedPath, targetDirectory, overwrite: true); - } - } - catch (Exception e) - { - exMoveDirectory = e; - ret = false; - LogError($"Failure to move Android component to its destination path. {e}"); - if (!String.IsNullOrEmpty(oldDestinationPath) && Directory.Exists(oldDestinationPath)) - { - LogError("Attempting to clean up."); - LogError($"Trying to remove directory '{targetDirectory}'"); - CommonUtilities.DeleteDirectoryRecursively(targetDirectory); - - try - { - CommonUtilities.MoveDirectory(oldDestinationPath, targetDirectory); - } - catch (Exception ex) - { - // ignore - LogError($"Failed to rename directory '{oldDestinationPath}' to '{targetDirectory}'. {ex}"); - } - } - } - - bool logError = false; - Exception rex = null; - try - { - CommonUtilities.DeleteDirectoryRecursively(temporaryPath); - if (!String.IsNullOrEmpty(oldDestinationPath)) - logError = !CommonUtilities.DeleteDirectoryRecursively(oldDestinationPath); - } - catch (Exception e) - { - logError = true; - ret = false; - rex = e; - // ignore - } - if (logError) - { - string message = $"Failed to remove old destination directory '{oldDestinationPath}'. User will have to remove it manually."; - if (rex != null) - LogError($"{message}. {rex}"); - else - LogError(message); - } - - if (exMoveDirectory != null) - throw exMoveDirectory; - - return ret; - } - - protected void GeneratePackageXml(string path) - { - LogDebug($"Generating {path}"); - - var settings = new XmlWriterSettings - { - CloseOutput = true, - Encoding = Encoding.UTF8, - Indent = false, - NamespaceHandling = NamespaceHandling.OmitDuplicates, - NewLineHandling = NewLineHandling.None, - OmitXmlDeclaration = false - }; - - using (var writer = XmlWriter.Create(path, settings)) - { - writer.WriteStartDocument(true); - // TODO: check if the namespace exists - writer.WriteStartElement("sdk", "repository", Repository.GetNamespaceUri("sdk")); - if (Repository.Namespaces != null) - { - foreach (var kvp in Repository.Namespaces) - { - if (string.Equals("xsi", kvp.Key, StringComparison.Ordinal)) - continue; - writer.WriteAttributeString("xmlns", kvp.Key, null, kvp.Value.NamespaceName); - } - } - - writer.WriteStartElement("license"); - writer.WriteAttributeString("id", LicenseID ?? String.Empty); - writer.WriteAttributeString("type", License?.Type ?? String.Empty); - writer.WriteString(License?.Text ?? String.Empty); - writer.WriteEndElement(); // license - - writer.WriteStartElement("localPackage"); - writer.WriteAttributeString("path", Path); - writer.WriteAttributeString("obsolete", Obsolete ? "true" : "false"); - - Info?.WritePackageXmlInfo(writer, Repository); - - writer.WriteStartElement("revision"); - if (Revision != null) - { - WriteRevisionPart(writer, "major", Revision.Major); - WriteRevisionPart(writer, "minor", Revision.Minor); - WriteRevisionPart(writer, "micro", Revision.Micro); - WriteRevisionPart(writer, "preview", Revision.Preview); - } - writer.WriteEndElement(); // revision - - writer.WriteStartElement("display-name"); - writer.WriteString(DisplayName); - writer.WriteEndElement(); // display-name - - writer.WriteStartElement("uses-license"); - writer.WriteAttributeString("ref", LicenseID ?? String.Empty); - writer.WriteEndElement(); // uses-license - - if (Dependencies != null && Dependencies.Count > 0) - { - writer.WriteStartElement("dependencies"); - foreach (Dependency dep in Dependencies) - { - if (dep == null) - continue; - writer.WriteStartElement("dependency"); - writer.WriteAttributeString("path", dep.Path ?? String.Empty); - writer.WriteEndElement(); //dependency - } - writer.WriteEndElement(); // dependencies - } - - writer.WriteEndElement(); // localPackage - - writer.WriteEndElement(); // repository - writer.WriteEndDocument(); - } - } - - void WriteRevisionPart(XmlWriter writer, string name, int value) - { - if (value < 0) - return; - - writer.WriteStartElement(name); - writer.WriteValue(value); - writer.WriteEndElement(); - } - - public virtual bool MatchesTo(IAndroidComponent other) - { - if (!(other is BasePackage)) - return false; - - if (ReferenceEquals(this, other)) - return true; - - if (IsPlatformSpecific && !SupportedPlatforms.SequenceEqual((other as BasePackage).SupportedPlatforms)) - return false; - - return string.Equals(Path, other.Path, StringComparison.Ordinal) && - Revision == other.Revision && - Channel == other.Channel; - } - - public virtual bool BasicMetadataEquals(BasePackage other) - { - if (other == null) - return false; - - if (ReferenceEquals(this, other)) - return true; - - // We compare only the properties that actually matter - if (!string.Equals(Path, other.Path, StringComparison.Ordinal)) - return false; - - if (!AreInfosEqual(Info, other.Info)) - return false; - - if (Obsolete != other.Obsolete) - return false; - - if (!Revision.Equals(other.Revision)) - return false; - - return true; - } - - bool AreInfosEqual(AndroidComponentInfo info1, AndroidComponentInfo info2) - { - // If only one of them is null return false - if ((info1 == null) != (info2 == null)) - return false; - - if (info1 != null && !info1.Equals(info2)) - return false; - - return true; - } - - // It's very simple in this case, we're not interested in deep comparison - // of the two instances, but rather whether they are uniquely identified - - // that is they have a different path+version combination. - public virtual bool Equals(BasePackage other) - { - if (!BasicMetadataEquals(other)) - return false; - - if (UniqueID != other.UniqueID) - return false; - - if (!Dependencies.AreEqual(other.Dependencies)) - return false; - - if (!Archives.AreEqual(other.Archives)) - return false; - - return true; - } - - public override bool Equals(object obj) - { - return Equals(obj as BasePackage); - } - - public override int GetHashCode() - { - int hashCode = base.GetHashCode(); - - hashCode = hashCode.XorWith(UniqueID.GetHashCode()); - hashCode = hashCode.XorWith(Path?.GetHashCode()); - hashCode = hashCode.XorWith(Info?.GetHashCode()); - hashCode = hashCode.XorWith(Obsolete.GetHashCode()); - hashCode = hashCode.XorWith(Revision?.GetHashCode()); - hashCode = hashCode.XorWith(Dependencies?.GetHashCode()); - return hashCode.XorWith(Archives?.GetHashCode()); - } - - protected abstract void LogError(string message); - protected abstract void LogWarning(string message); - protected abstract void LogInfo(string message); - protected abstract void LogDebug(string message); - - private bool GetPreview() - { - if (Info is AndroidComponentInfoPlatform platform) - { - return platform.Preview; - } - return false; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Channel.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Channel.cs deleted file mode 100644 index 132690fad68..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Channel.cs +++ /dev/null @@ -1,88 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Describes a single Android SDK channel. Google currently define 4 channels: - /// - /// - /// stable - /// - /// - /// beta - /// - /// - /// dev - /// - /// - /// canary - /// - /// - /// Note however that the list is defined directly in the Android SDK manifest document and may be - /// changed by Google at any time. - /// - public sealed class Channel : ItemWithID, IEquatable - { - /// - /// Gets the channel name - /// - /// Channel name - public string Name { get; } - - /// - /// Initializes a new instance of the class. - /// - /// Identifier. - /// Name. - public Channel (string id, string name) : base (id) - { - if (String.IsNullOrEmpty (name)) - throw new ArgumentException ("Must not be null or empty", nameof (name)); - Name = name; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public bool Equals (Channel other) - { - if (other == null) - return false; - - return Equals (other as ItemWithID); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as Channel); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - return base.GetHashCode (); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ConfigManager.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ConfigManager.cs deleted file mode 100644 index fc6258a2ad4..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ConfigManager.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Xml; -using System.Xml.Linq; -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK.Manager -{ - public class ConfigManager - { - const string AppName = "AndroidSDKManager"; - const string PropertiesRootNode = "SDKManagerProperties"; - const string PropertyNode = "Property"; - - Dictionary properties; - - /// - /// SDK Manager configuration folder path - /// - /// - public static string ConfigFolder { - get { - string configFolder; - if (Platform.IsMac) { - var home = Environment.GetFolderPath (Environment.SpecialFolder.UserProfile); - configFolder = Path.Combine (home, "Library", "Preferences"); - } else { - configFolder = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData); - if (Platform.IsWindows) - configFolder = Path.Combine (configFolder, "Config"); - } - return Path.Combine (configFolder, AppName); - } - } - - string filePath; - string FilePath { - get { - if (filePath == null) - filePath = Path.Combine (ConfigFolder, "properties.xml"); - - return filePath; - } - } - - internal ConfigManager () - { - LoadProperties (); - } - - internal void SetProperty (string key, string value) - { - if (properties.ContainsKey (key)) { - if (string.Equals (properties [key], value, StringComparison.Ordinal)) - return; - properties.Remove (key); - } - - properties.Add (key, value); - } - - internal string GetProperty (string key, string defaultValue) - { - bool success = properties.TryGetValue (key, out string value); - return success ? value : defaultValue; - } - - void LoadProperties () - { - properties = new Dictionary (StringComparer.Ordinal); - if (!File.Exists (FilePath)) - return; - - try - { - var element = XElement.Load (FilePath); - foreach (var node in element.Descendants (PropertyNode)) { - var key = node.Attribute ("key").Value; - var value = node.Attribute ("value").Value; - if (String.IsNullOrEmpty (key)) - continue; - - properties.Add (key, value); - } - } - catch (XmlException ex) - { - // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/723620 - // Overwrite the broken config with an empty xml (we write default property values there later) - Logger.Warning ($"Failed to read the config, resetting it.\nError details: {ex}"); - SaveProperties (); - } - } - - - internal void SaveProperties () - { - var filePath = FilePath; - if (!File.Exists (filePath)) { - var dir = Path.GetDirectoryName (filePath); - if (!Directory.Exists (dir)) - Directory.CreateDirectory (dir); - } - XmlWriter xmlWriter = XmlWriter.Create(FilePath); - - xmlWriter.WriteStartDocument(); - xmlWriter.WriteStartElement(PropertiesRootNode); - foreach (var keyValue in properties) { - xmlWriter.WriteStartElement(PropertyNode); - xmlWriter.WriteAttributeString ("key", keyValue.Key); - xmlWriter.WriteAttributeString ("value", keyValue.Value); - } - xmlWriter.WriteEndElement(); - xmlWriter.Close(); - } - } -} \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Constants.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Constants.cs deleted file mode 100644 index 8a280aa0731..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Constants.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - public static partial class Constants - { - public static class ComponentPaths - { - public const string BuildTools = "build-tools;"; - public const string CMake = "cmake;"; - public const string Emulator = "emulator"; - public const string LLDB = "lldb;"; - public const string NDK = "ndk-bundle"; - public const string PlatformTools = "platform-tools"; - public const string ToolsObsolete = "tools"; - public const string Tools = "cmdline-tools"; - public const string ToolsLatest = "cmdline-tools;latest"; - - public const string Platforms = "platforms"; - - public const string HypervisorDriver = "extras;google;Android_Emulator_Hypervisor_Driver"; - } - - public static partial class RequiredComponentVersions - { - // This class has properties which are auto generated by the GenerateRequiredComponentVersions MSBuild Target - - // this defaults are used by the IDEs to complete the required components on the auto-sdk process - // values are in sync with the GetAndroidDependencies target result - public static readonly string[] RequiredComponents = { - $"build-tools/{RequiredBuildToolsVersion}@{RequiredBuildToolsVersion}", - $"platform-tools@{RequiredPlatformToolsVersion}", - $"cmdline-tools/{RequiredCommandLineToolsVersion}@{RequiredCommandLineToolsVersion}", - }; - } - } -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Dependency.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Dependency.cs deleted file mode 100644 index 1a03177aaf5..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Dependency.cs +++ /dev/null @@ -1,102 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Describes a single package dependency - /// - public sealed class Dependency : IEquatable - { - /// - /// Manifest path to the dependency - /// - /// Dependency path - public string Path { get; } - - /// - /// Gets the minimum revision of the dependency package - /// - /// The minimum revision. - public AndroidRevision MinRevision { get; } - - public AndroidSDKPlatform Platform { get; set; } = AndroidSDKPlatform.Unknown; - public bool IsPlatformSpecific => Platform != AndroidSDKPlatform.Any && Platform != AndroidSDKPlatform.Unknown; - - internal Dependency (string path, AndroidRevision minRevision = null) - { - if (String.IsNullOrEmpty (path)) - throw new ArgumentException ("must not be null or empty", nameof (path)); - - Path = path; - MinRevision = minRevision; - } - - internal Dependency (Dependency other) - { - if (other == null) - throw new ArgumentNullException (nameof (other)); - - Path = other.Path; - if (other.MinRevision != null) - MinRevision = new AndroidRevision (other.MinRevision); - Platform = other.Platform; - } - - /// - /// Determines whether the specified is equal to the - /// current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public bool Equals (Dependency other) - { - if (other == null) - return false; - - if (ReferenceEquals (this, other)) - return true; - - if (!string.Equals (Path, other.Path, StringComparison.Ordinal)) - return false; - - if (MinRevision == null) { - if (other.MinRevision != null) - return false; - } else if (!MinRevision.Equals (other.MinRevision)) - return false; - - return Platform == other.Platform; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as Dependency); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - hashCode = hashCode.XorWith (Path?.GetHashCode ()); - return hashCode.XorWith (MinRevision?.GetHashCode ()); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Helper.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Helper.cs deleted file mode 100644 index 0fe753a1deb..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Helper.cs +++ /dev/null @@ -1,472 +0,0 @@ -// -// Helper.cs -// -// Author: -// Vsevolod Kukol -// -// Copyright (c) 2017, Microsoft, Inc -// - -using System; -using System.IO; -using System.Net; -using System.Net.Http; -using ICSharpCode.SharpZipLib.Zip; -using Xamarin.Installer.Common; -using System.Collections.Concurrent; -using System.Threading.Tasks; -using Xamarin.Installer.AndroidSDK.Common; -using System.Threading; -using System.Linq; - -#if !WINDOWS -using Mono.Unix.Native; -#endif - -using System.Runtime.InteropServices; - -namespace Xamarin.Installer.AndroidSDK.Manager -{ - public class Helper : IHelpers - { - public static readonly TimeSpan HttpTimeout = TimeSpan.FromSeconds (Platform.IsWindows ? 60 : 10); - static string homeDirectory; - ConfigManager config = new ConfigManager (); - - public string CacheFolder { get; set; } - - readonly string manifestFilePath; - - static ConcurrentDictionary> stringDownloadCache = new ConcurrentDictionary> (); - - public Helper (string cacheFolder = null, string manifestFilePath = null) - { - CacheFolder = cacheFolder; - this.manifestFilePath = manifestFilePath; - } - - public static string HomeDirectory { - get - { - if (string.IsNullOrEmpty(homeDirectory)) { - homeDirectory = Environment.GetEnvironmentVariable("HOME"); - if (String.IsNullOrEmpty(homeDirectory) || !Directory.Exists(homeDirectory)) { - homeDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - } - } - return homeDirectory; - } - } - - string IHelpers.HomeDirectory { - get { - return HomeDirectory; - } - } - - public bool IsArm64 - { - get { - return RuntimeInformation.ProcessArchitecture == Architecture.Arm64; - } - } - - public bool Is64BitOS { - get { - return Environment.Is64BitOperatingSystem; - } - } - - public bool IsCaseSensitiveFileSystem { - get { return true; } // TODO - } - - public string UserName { - get { - if (Platform.IsWindows) - return Environment.UserName; - return Environment.GetEnvironmentVariable ("USER"); - } - } - - public bool DownloadToString (Uri url, out string output) - { -#if DEBUG - // DEBUG: support setting XAMARIN_ANDROID_MANIFEST_URL=file:///… for local manifest authoring. - if (url.Scheme == "file") - { - output = File.ReadAllText(url.LocalPath); - return true; - } -#else - // Release: only allow https://, plus the in-box file:// fallback manifest that - // ships alongside this assembly (XamarinRepository.GetFallbackManifestUrl), or a - // local manifest path explicitly supplied by InstallAndroidDependencies. - if (url.Scheme == "file") { - var assemblyDir = Path.GetDirectoryName (typeof (Helper).Assembly.Location); - var requestedDir = Path.GetDirectoryName (url.LocalPath); - if ((!string.IsNullOrEmpty (manifestFilePath) && string.Equals (manifestFilePath, url.LocalPath, StringComparison.OrdinalIgnoreCase)) || - (!string.IsNullOrEmpty (assemblyDir) && string.Equals (assemblyDir, requestedDir, StringComparison.OrdinalIgnoreCase))) { - output = File.ReadAllText (url.LocalPath); - return true; - } - Logger.Warning ($"Ignoring file:// manifest URL '{url}': file:// is only honored for an explicit local manifest path or the in-box fallback manifest in shipped builds."); - output = null; - return false; - } - if (url.Scheme != "https") { - Logger.Warning ($"Ignoring manifest URL '{url}': only https:// URLs are honored in shipped builds."); - output = null; - return false; - } -#endif - - // FIXME: returning false on failure doesn't make Installer.Discover return false. - // hence we need a hard throw on failure to detect it on higher levels - //try { - - using (var client = HttpClientProvider.CreateHttpClient (url)) { - client.Timeout = HttpTimeout; - var req = new HttpRequestMessage (HttpMethod.Get, url); - - if (stringDownloadCache.TryGetValue(url, out Tuple cache)) { - req.Headers.IfModifiedSince = cache.Item1; - output = cache.Item2; - } - - //try { - using (var res = client.SendAsync (req, HttpCompletionOption.ResponseHeadersRead).Result) { - if (res.StatusCode == HttpStatusCode.NotModified) { - output = cache.Item2; - return true; - } - if (res.StatusCode != HttpStatusCode.OK) { - Logger.Warning ($"Unable to download manifest xml from {url}. Status Code: {res.StatusCode} - {(int)res.StatusCode}"); - output = null; - return false; - } - output = res.Content.ReadAsStringAsync ().Result; - DateTimeOffset? lastModified = res.Content.Headers.LastModified; - if (lastModified.HasValue) - stringDownloadCache[url] = Tuple.Create (lastModified.Value, output); - return true; - } - //} catch (Exception ex) { - // Logger.Exception ($"Downloading '{url}' failed", ex); - // output = null; - // return false; - //} - } - } - - public string GetPathForDownloadId (Guid id) - { - return Path.Combine (Path.GetTempPath (), "xamarin-android-sdk", id.ToString () + ".zip"); - } - - public ulong GetUrlContentLength (Uri url) - { - using (var client = HttpClientProvider.CreateHttpClient (url)) { - client.Timeout = HttpTimeout; - var request = new HttpRequestMessage(HttpMethod.Head, url); - var resp = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result; - if (resp.IsSuccessStatusCode) - return (ulong)(resp.Content.Headers.ContentLength ?? 0); - return 0; - } - } - - public bool IsSpecialFile (string filePath) - { - return false; - } - - public void CopySpecialFile (string source, string target) - { - throw new NotImplementedException (); - } - - public class CustomTooLongPathException : Exception - { - public Exception OriginalException { get; set; } - } - - public string Unzip (string baseDirectory, string archivePath, string fileOwnerName = null) - { - return Unzip (baseDirectory, archivePath, fileOwnerName, progressCallback: null); - } - - public string Unzip (string baseDirectory, string archivePath, string fileOwnerName = null, - InstallationProgressEventArgs.InstallationProgressActionDelegate progressCallback = null) - { - if (string.IsNullOrEmpty (baseDirectory)) - throw new ArgumentNullException (nameof (baseDirectory), "No base directory given, unable to unzip."); - if (string.IsNullOrEmpty (archivePath)) - throw new ArgumentNullException (nameof (archivePath), "No ZIP archive specified."); - Logger.Info ($"Unzipping file '{archivePath}' to directory '{baseDirectory}'"); - - if (!Directory.Exists (baseDirectory)) { - try { - Directory.CreateDirectory (baseDirectory); - // TODO: set directory owner and permissions - } catch (Exception ex) { - Logger.Exception ($"Failed to create base directory '{baseDirectory}' to unzip archive.", ex); - return null; - } - } - - string lastDestPath = String.Empty; - ZipFile zip = null; - - try - { - zip = new ZipFile (archivePath); - - float minProgressDelta = 5f; // percents - float lastProgress = 0f; - float progress; - - ulong totalSize = DirectorySizeMonitoringTimer.CalculateTotalSize (zip); - ulong currentSize = 0, gradualSize; - try { - progressCallback?.Invoke (0f); - } catch (Exception ex) { - Logger.Error ($"[Unzip] progress callback exception: {ex}"); - } - - string fullBaseDirectory = Path.GetFullPath (baseDirectory).TrimEnd (Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar; - - foreach (ZipEntry entry in zip) { - string destPath = Path.Combine (baseDirectory, entry.Name); - lastDestPath = destPath; - - if (!Path.GetFullPath (destPath).StartsWith (fullBaseDirectory, StringComparison.OrdinalIgnoreCase)) { - throw new Exception ($"Archive file '{archivePath}' has parent traversal in paths"); - } - - if (entry.IsDirectory) { - Directory.CreateDirectory (destPath); - SafeSetLastWriteTime (destPath, entry.DateTime); - continue; - } - - Directory.CreateDirectory (Path.GetDirectoryName (destPath)); - - byte [] buf = new byte [4096]; - int n = 0; - gradualSize = 0; - ulong iteration = 0; - using (var fs = new FileStream (destPath, FileMode.Create, FileAccess.Write, FileShare.None)) { - using (var inZip = zip.GetInputStream (entry)) { - while ((n = inZip.Read (buf, 0, buf.Length)) > 0) { - fs.Write (buf, 0, n); - gradualSize += (ulong) n; - iteration++; - - if (iteration % 1000 == 0 && progressCallback != null) { - progress = (currentSize + gradualSize) * 100f / totalSize; - if (progress - lastProgress > minProgressDelta) { - try { - progressCallback?.Invoke (progress); - } catch (Exception ex) { - Logger.Error ($"[Unzip] progress callback exception: {ex}"); - } - lastProgress = progress; - } - } - } - } - currentSize += (ulong) fs.Length; - } - SafeSetLastWriteTime (destPath, entry.DateTime); - SetFileAttributes (destPath, entry.IsDOSEntry, entry.ExternalFileAttributes); - // TODO: set owner - - progress = currentSize * 100f / totalSize; - if (progress - lastProgress > minProgressDelta) { - try { - progressCallback?.Invoke (progress); - } catch (Exception ex) { - Logger.Error ($"[Unzip] progress callback exception: {ex}"); - } - lastProgress = progress; - } - } - - try { - progressCallback?.Invoke (100f); - } catch (Exception ex) { - Logger.Error ($"[Unzip] progress callback exception: {ex}"); - } - } catch (DirectoryNotFoundException ex) { - Logger.Error ($"Unzip failed with DirectoryNotFoundException error: {ex}"); - if (lastDestPath.Length >= 240) { - Logger.Error ($"Try enabling long paths support to resolve this issue: https://blogs.msdn.microsoft.com/jeremykuhne/2016/07/30/net-4-6-2-and-long-paths-on-windows-10/"); - throw new CustomTooLongPathException { OriginalException = ex }; - } - throw; - } finally { - zip?.Close (); - } - - string topDirectory = string.Empty; - string [] entries = Directory.GetDirectories (baseDirectory); - - if (entries.Length == 1) - topDirectory = entries [0]; - - string ret = Path.GetFullPath (Path.Combine (baseDirectory, topDirectory)); - Logger.Info ($"Archive unzipped to '{ret}'"); - - return ret; - } - - static void SafeSetLastWriteTime (string path, DateTime stamp) - { - try { - if (Directory.Exists (path)) - Directory.SetLastWriteTime (path, stamp); - else if (File.Exists (path)) - File.SetLastWriteTime (path, stamp); - } catch { - // Just ignoring this exception, time stamp is not THAT important... - } - } - - static void SetFileAttributes (string filePath, bool dosAttributes, int zipAttributes) - { - if (String.IsNullOrEmpty(filePath) || !File.Exists(filePath)) - return; - if (dosAttributes && zipAttributes != -1) { - var fileAttributes = (FileAttributes)zipAttributes; - fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttributes.Hidden); - File.SetAttributes(filePath, fileAttributes); - } else - File.SetAttributes(filePath, FileAttributes.Normal); - - #if !WINDOWS - if (Platform.IsWindows) - return; - - zipAttributes = (zipAttributes >> 16); - - if (zipAttributes == -1) - return; - - FilePermissions permissions = unchecked((FilePermissions)zipAttributes); - if (permissions == 0) { - // 644 octal - permissions = FilePermissions.S_IRUSR | - FilePermissions.S_IWUSR | - FilePermissions.S_IRGRP | - FilePermissions.S_IROTH; - } else if ((permissions & FilePermissions.S_IRUSR) == 0) - permissions |= FilePermissions.S_IRUSR; // owner must be able to read the file - - if (Syscall.chmod(filePath, permissions) == -1) - throw new InvalidOperationException (String.Format("Failed to set file attributes for '{0}'. {1}", - filePath, Stdlib.strerror(Stdlib.GetLastError()))); - #endif - } - - public bool URLExists (Uri url) - { - throw new NotImplementedException (); - } - - public string GetRegistryKeyValue (string subKeyPath, string keyName, bool check64Node) - { - throw new NotImplementedException (); - } - - public string GetPluralString (string s, string p, int n) - { - return n == 1 ? s : p; - } - - public string GetString (string s) - { - return s; - } - - public string GetProperty (string key, string defaultValue = "") - { - return config.GetProperty (key, defaultValue); - } - - public void SetProperty (string key, string value) - { - config.SetProperty (key, value); - config.SaveProperties (); - } - - const int NetworkCheckRetryCount = 3; - static readonly TimeSpan NetworkCheckRetryDelay = TimeSpan.FromSeconds (1); - - public async Task CheckIfNetworkIsAvailableAsync () - { - try { - return await RetryIfTimeoutAsync (CheckIfNetworkAvailable, NetworkCheckRetryCount, NetworkCheckRetryDelay); - } catch (TimeoutException) { - return false; - } catch (TaskCanceledException) { - return false; - } - } - - static async Task RetryIfTimeoutAsync (Func> action, int retryCount, TimeSpan retryDelay) - { - for (int attempt = 0; ; attempt++) { - try { - return await action ().ConfigureAwait (false); - } catch (Exception exception) when (attempt < retryCount && (exception is TimeoutException || exception is TaskCanceledException)) { - Logger.Warning ($"[Resiliency.Polly.Policies]: Delegate has thrown {exception}, retrying..."); - } - await Task.Delay (retryDelay).ConfigureAwait (false); - } - } - - private Uri GetUrlToCheckIfNetworkAvailable() - { - var customURL = Environment.GetEnvironmentVariable("ANDROID_SDK_INSTALLER_CHECK_NETWORK_URL"); - if (!string.IsNullOrEmpty(customURL) && Uri.TryCreate(customURL, UriKind.Absolute, out Uri url)) - { - return url; - } else - { - return new Uri("https://dotnet.microsoft.com/"); - } - } - - async Task CheckIfNetworkAvailable () - { - try { - var uri = GetUrlToCheckIfNetworkAvailable(); - using (var client = HttpClientProvider.CreateHttpClient (uri)) { - client.Timeout = HttpTimeout; - var request = new HttpRequestMessage (HttpMethod.Get, uri); - using (var response = await client.SendAsync (request, HttpCompletionOption.ResponseHeadersRead)) - return response.IsSuccessStatusCode; - } - } catch (TimeoutException) { - throw; - } catch (TaskCanceledException) { - throw; - } catch (HttpRequestException) { - return false; - } catch (AggregateException ex) { - foreach (var innerEx in ex.Flatten ().InnerExceptions) - if (!(innerEx is HttpRequestException)) - Logger.Warning ($"An exception occurred while checking network availability.\n{innerEx}"); - - if (ex.Flatten ().InnerException is TaskCanceledException) - throw ex.Flatten ().InnerException; - - return false; - } catch (Exception ex) { - Logger.Warning ($"An exception occurred while checking network availability.\n{ex}"); - return false; - } - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/HttpClientProvider.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/HttpClientProvider.cs deleted file mode 100644 index 6006b032254..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/HttpClientProvider.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Net.Security; -using System.Security.Cryptography.X509Certificates; - -namespace Xamarin.Installer.AndroidSDK.Manager -{ - /// - /// Creates a HttpClient. - /// - public static class HttpClientProvider - { - static Func httpClientFactory; - - /// - /// Allows the default HttpClient creation to be overridden. - /// - /// Factory method used to create the HttpClient. - public static void SetHttpClientFactory (Func factory) - { - httpClientFactory = factory; - } - - /// - /// Creates a new HttpClient. - /// - /// The HttpClient. - /// The request url. - /// The cookie container to use for the HttpClient. - /// The decompression methods to use for the HttpClient. - public static HttpClient CreateHttpClient (Uri uri, CookieContainer cookieContainer = null, DecompressionMethods automaticDecompression = DecompressionMethods.None) - { - if (httpClientFactory != null) - return httpClientFactory.Invoke (uri); - - var handler = new HttpClientHandler - { - AutomaticDecompression = automaticDecompression, - CheckCertificateRevocationList = true, - ServerCertificateCustomValidationCallback = SslValidationCallback - }; - - if (cookieContainer != null) - { - handler.CookieContainer = cookieContainer; - } - - if (WebRequest.DefaultWebProxy != null) - handler.Proxy = WebRequest.DefaultWebProxy; - - var client = new HttpClient(handler); - return client; - } - - static bool SslValidationCallback(HttpRequestMessage request, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) - { - if (sslPolicyErrors == SslPolicyErrors.None) - return true; - - if (sslPolicyErrors != SslPolicyErrors.RemoteCertificateChainErrors) - return false; - - // If all we have is "Revocation Unknown" errors, then accept the certificate. Works around Enterprise proxy issues - // such as the one described in https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2057013 - foreach (var status in chain.ChainStatus) - { - if (status.Status != X509ChainStatusFlags.NoError && status.Status != X509ChainStatusFlags.RevocationStatusUnknown) - return false; - } - - return true; - } - } -} \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidApiLevel.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidApiLevel.cs deleted file mode 100644 index c90169182dd..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidApiLevel.cs +++ /dev/null @@ -1,24 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Helper interface representing a component's API level - /// - public interface IAndroidApiLevel - { - /// - /// Gets the API level. - /// - /// The API level. - string ApiLevel { get; } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidComponent.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidComponent.cs deleted file mode 100644 index 57a2e84ce88..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidComponent.cs +++ /dev/null @@ -1,165 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Collections.Generic; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Interface fully describing a single Android component - /// - public interface IAndroidComponent - { - /// - /// Occurs when status changes. - /// - event EventHandler StatusChanged; - - /// - /// true if this component is required for an instance of Android SDK to work properly - /// - bool IsEssential { get; } - - /// - /// Gets a value indicating whether this component ignores installation failures. - /// - /// true if installation failure is ignored; otherwise, false. - bool IgnoreFailure { get; } - - /// - /// Gets or sets a value indicating whether the component is present in the given Android SDK instance on disk. - /// - /// true if present; otherwise, false. - bool Present { get; } - - /// - /// Gets or sets a value indicating whether this component has to be - /// updated. It will be set to true also of is false - /// - /// true if needs update; otherwise, false. - bool NeedsUpdate { get; } - - /// - /// Type of the component. This is a map from the textual type name in the repository manifest into an - /// enumeration for easier searching and component identification - /// - /// The type of the component. - AndroidComponentType ComponentType { get; } - - /// - /// Gets the unique identifier of this particular instance. The ID is not persistent, it is valid only within - /// a single installer session and used to retrieve download information from the hosting application. - /// - /// - /// The unique identifier. - Guid UniqueID { get; } - - /// - /// Gets package path as found in the SDK repository manifest. Note that paths aren't necessarily unique, there - /// may exist several packages with the same path but different version. - /// - /// The manifest path. - string Path { get; } - - /// - /// Gets the file system path where the package is (or will be) found, relative to the given Android SDK root - /// directory. This is, essentially, value of the property converted to the proper path - /// representation for the current operating system. - /// - /// The file system path. - string FileSystemPath { get; } - - /// - /// Gets a value indicating whether this is obsolete. - /// - /// true if obsolete; otherwise, false. - bool Obsolete { get; } - - /// - /// Type-specific information about this component - /// - /// Component type-specific information - AndroidComponentInfo Info { get; } - - /// - /// Gets the available component revision. - /// - /// Component revision. - AndroidRevision Revision { get; } - - /// - /// Gets the revision of the component as found in the given Android SDK root, if any. - /// - /// Revision of the installed component - AndroidRevision InstalledRevision { get; } - - /// - /// Gets the display name of the component - /// - /// Component display name - string DisplayName { get; } - - /// - /// Gets the detailed description of the component - /// - /// Detailed description of the component - string DetailedDescription { get; } - - /// - /// Gets the component dependencies, if any. - /// - /// Component dependencies - IList Dependencies { get; } - - /// - /// Gets the component channel. - /// - /// Component channel - Channel Channel { get; } - - /// - /// Gets the component archives. Only archives valid for the current operating system will be found here. - /// - /// Component archives - IList Archives { get; } - - /// - /// Gets the component license. - /// - /// Component license - License License { get; } - - /// - /// Gets the URL of the manifest from which the component description was loaded. - /// - /// The manifest URL. - Uri ManifestURL { get; } - - /// - /// Hosting application can set this to true if it wants the installer to ignore value of the - /// property and force (re)installation of the component. This property must be set before the component is passed to the - /// method. - /// - /// true to force installation; otherwise, false. - bool ForceInstallation { get; set; } - - /// - /// ID of the license the component uses - /// - string LicenseID { get; set; } - - /// - /// Compares properties related to Path and Revision, - /// and returns True, if they are same for the matching components. - /// - /// Component to compare with - /// - bool MatchesTo (IAndroidComponent other); - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidComponentInternal.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidComponentInternal.cs deleted file mode 100644 index 6a28f594672..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IAndroidComponentInternal.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2018, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Collections.Generic; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - interface IAndroidComponentInternal - { - void Remove (string androidSDKRoot); - void PerformDetection (string androidSDKRoot, bool isRefresh = false); - void RefreshMetadata (IAndroidComponent component, bool ignoreInstalledState = true); - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IArchive.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IArchive.cs deleted file mode 100644 index f05530d9c1f..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IArchive.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - public interface IArchive - { - /// - /// Gets the archive size - /// - /// Archive size - ulong Size { get; } - - /// - /// Gets the SHA1 checksum of the archive - /// - /// SHA1 checksum - string Checksum { get; } - - /// - /// Gets the archive URL - /// - /// Archive URL - Uri Url { get; } - - /// - /// Gets the target (host) operating system of the archive (if any) - /// - /// Host operating system - string HostOS { get; } - - /// - /// Mapping of into one of the enumeration members - /// - /// Archive platform. - AndroidSDKPlatform Platform { get; } - - /// - /// Native word size of the host operating system. - /// - /// Host operating system word size - uint HostBits { get; } - - /// - /// CPU Architecture of the host operating system. - /// - /// Host operating CPU architecture - string HostArch { get; } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IJdkComponent.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IJdkComponent.cs deleted file mode 100644 index 0a04fb4ba7a..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/IJdkComponent.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - public interface IJdkComponent - { - Guid UniqueID { get; } - - string DisplayName { get; } - - bool Obsolete { get; } - - bool Preview { get; } - - string LicenseID { get; } - - PackageVendor Vendor { get; } - - AndroidRevision Revision { get; } - - /// - /// Gets the component archives - /// - /// Component archives - IList Archives { get; } - - IEnumerable GetValidArchivesForSystem(); - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ILicensesStorage.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ILicensesStorage.cs deleted file mode 100644 index de4ece78fc7..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ILicensesStorage.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - public interface ILicensesStorage - { - /// - /// Returns if the license was accepted in this Android SDK - /// - /// Android Sdk path - /// license to check - /// true if the license is accepted, false otherwise - bool IsLicenseAccepted(string androidSdkPath, License license); - - /// - /// Accept licenses - /// - /// Android Sdk path - /// Java Sdk path - /// specific cmdLine-tools path to use - /// list of licenses to accept - /// cancellation token - /// log file path - /// throw exception with arguments validation error - Task AcceptLicensesAsync( - string androidSdkPath, - string javaSdkPath, - string cmdLineToolsPath, - IEnumerable licenses, - CancellationToken token, - string logPath = null, - bool throwsErrorIfValidationFailed = false); - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ItemWithID.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ItemWithID.cs deleted file mode 100644 index 837d55cbf7b..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ItemWithID.cs +++ /dev/null @@ -1,62 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// - -#nullable enable - -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Base class for all types with a string identifier - /// - public abstract class ItemWithID : IEquatable - { - /// - /// Gets the identifier string. - /// - /// The identifier string - public string ID { get; } - - /// - /// Initializes a new instance of the class. - /// - /// Identifier (required) - protected ItemWithID (string id) - { - if (String.IsNullOrEmpty (id)) - throw new ArgumentException ("Must not be null or empty", nameof (id)); - ID = id; - } - - public bool Equals (ItemWithID? other) - { - if (other == null) - return false; - - if (ReferenceEquals (this, other)) - return true; - - if (!string.Equals (ID, other.ID, StringComparison.Ordinal)) - return false; - - return true; - } - - public override bool Equals (object? obj) - { - return Equals (obj as ItemWithID); - } - - public override int GetHashCode () - { - return ID?.GetHashCode () ?? 0; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ItemWithIDAndDisplay.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ItemWithIDAndDisplay.cs deleted file mode 100644 index 5f3a4eedf72..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/ItemWithIDAndDisplay.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc (http://microsoft.com) -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Abstract base class for all the clases that have some sort of identifier and a display name. - /// - public abstract class ItemWithIDAndDisplay : ItemWithID - { - /// - /// Gets the display name of the item - /// - /// Item display name - public string Display { get; } - - /// - /// Initializes a new instance of the class. - /// - /// Identifier. - /// Display. - protected ItemWithIDAndDisplay (string id, string display) : base (id) - { - Display = display ?? String.Empty; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/JdkArchive.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/JdkArchive.cs deleted file mode 100644 index da3b9a016a2..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/JdkArchive.cs +++ /dev/null @@ -1,38 +0,0 @@ -#nullable enable - -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - public class JdkArchive : Archive, IEquatable - { - public JdkArchive(string hostOS) : base(hostOS) - { - } - - public string? PayloadFileName { get; set; } - - public override bool IsValidForSystem() - { - return IsPlatformValid() && IsHostArchValid(); - } - - public override bool Equals(Object? obj) - { - return Equals(obj as JdkArchive); - } - - public bool Equals(JdkArchive? other) - { - if (other == null) - return false; - - return base.Equals(other); - } - - public override int GetHashCode() - { - return this.HostOS.GetHashCode(); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/JdkPackage.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/JdkPackage.cs deleted file mode 100644 index 4a4e45c925a..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/JdkPackage.cs +++ /dev/null @@ -1,43 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - public class JdkPackage : IJdkComponent - { - public JdkPackage(string displayName, bool obsolete, bool preview, string licenseId, PackageVendor vendor, AndroidRevision revision, List archives) - { - DisplayName = displayName; - Obsolete = obsolete; - Preview = preview; - Vendor = vendor; - Revision = revision; - Archives = archives; - LicenseID = licenseId; - } - - public Guid UniqueID { get; } = Guid.NewGuid(); - - public string DisplayName { get; } - - public bool Obsolete { get; } - - public bool Preview { get; } - - public string LicenseID { get; } - - public PackageVendor Vendor { get; } - - public AndroidRevision Revision { get; } - - public IList Archives { get; } - - public IEnumerable GetValidArchivesForSystem() - { - return Archives.Where(x => x.IsValidForSystem()); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/License.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/License.cs deleted file mode 100644 index 26234b90e18..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/License.cs +++ /dev/null @@ -1,86 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Represents component License - /// - public sealed class License : ItemWithID, IEquatable - { - /// - /// Content type. Currently only text is defined. - /// - /// Content type. - public string Type { get; } - - /// - /// Gets text of the license. - /// - /// License text - public string Text { get; } - - internal License (string id, string type, string text) : base (id) - { - Type = type; - Text = text; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public bool Equals (License other) - { - if (other == null) - return false; - - if (ReferenceEquals (this, other)) - return true; - - if (!string.Equals (ID, other.ID, StringComparison.Ordinal)) - return false; - - if (!string.Equals (Type, other.Type, StringComparison.Ordinal)) - return false; - - if (!string.Equals (Text, other.Text, StringComparison.Ordinal)) - return false; - - return true; - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as License); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = 0; - - hashCode = hashCode.XorWith (ID?.GetHashCode ()); - hashCode = hashCode.XorWith (Type?.GetHashCode ()); - return hashCode.XorWith (Text?.GetHashCode ()); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageLibrary.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageLibrary.cs deleted file mode 100644 index b21f34ebdf3..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageLibrary.cs +++ /dev/null @@ -1,85 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Describes a single library contained in a package - /// - public sealed class PackageLibrary : IEquatable - { - /// - /// Gets the local path of the library JAR archive. - /// - /// Path to the JAR archive - public string LocalJarPath { get; internal set; } - - /// - /// Gets the library name - /// - /// Library name - public string Name { get; internal set; } - - /// - /// Gets the library description. - /// - /// The description. - public string Description { get; internal set; } - - /// - /// Determines whether the specified is equal to the - /// current . - /// - /// The to compare with the current . - /// true if the specified is equal to the - /// current ; otherwise, false. - public bool Equals (PackageLibrary other) - { - if (other == null) - return false; - - if (!ReferenceEquals (this, other)) - return false; - - return string.Equals (LocalJarPath, other.LocalJarPath, StringComparison.Ordinal); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as PackageLibrary); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (LocalJarPath != null) - hashCode = hashCode.XorWith (LocalJarPath.GetHashCode ()); - - if (Name != null) - hashCode = hashCode.XorWith (Name.GetHashCode ()); - - if (Description != null) - hashCode = hashCode.XorWith (Description.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageMetadata.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageMetadata.cs deleted file mode 100644 index 7ab34e8dee6..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageMetadata.cs +++ /dev/null @@ -1,57 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2018, Microsoft Corp. (https://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - public class PackageMetadata - { - public bool Present { get; set; } - public bool NeedsUpdate { get; set; } - public string Path { get; set; } - public string FileSystemPath { get; set; } - public bool Obsolete { get; set; } - public bool Preview => GetPreview (); - public AndroidComponentInfo Info { get; set; } - public AndroidRevision Revision { get; set; } - public AndroidRevision InstalledRevision { get; set; } - public string DisplayName { get; set; } - public IList Dependencies { get; set; } - public IList Archives { get; set; } - public string LicenseID { get; set; } - - public PackageMetadata (IAndroidComponent component) - { - if (component == null) - throw new ArgumentNullException (nameof (component)); - - Present = component.Present; - NeedsUpdate = component.NeedsUpdate; - Path = component.Path; - FileSystemPath = component.FileSystemPath; - Obsolete = component.Obsolete; - Info = component.Info; - Revision = component.Revision; - InstalledRevision = component.InstalledRevision; - DisplayName = component.DisplayName; - Dependencies = component.Dependencies != null ? new List (component.Dependencies) : null; - Archives = component.Archives != null ? new List (component.Archives) : null; - LicenseID = component.LicenseID; - } - - bool GetPreview () - { - if (Info is AndroidComponentInfoPlatform platform) { - return platform.Preview; - } - return false; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageTag.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageTag.cs deleted file mode 100644 index efe22b3fe65..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageTag.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Describes a package tag. - /// - public sealed class PackageTag : ItemWithIDAndDisplay, IEquatable - { - public PackageTag (string id, string display) : base (id, display) - {} - - /// - /// Determines whether the specified is equal to the - /// current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public bool Equals (PackageTag other) - { - if (other == null) - return false; - - if (!ReferenceEquals (this, other)) - return false; - - if (!string.Equals (ID, other.ID, StringComparison.Ordinal)) - return false; - - return string.Equals (Display, other.Display, StringComparison.Ordinal); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as PackageTag); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (ID != null) - hashCode = hashCode.XorWith (ID.GetHashCode ()); - if (Display != null) - hashCode = hashCode.XorWith (Display.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageVendor.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageVendor.cs deleted file mode 100644 index 7caf450d5bd..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/PackageVendor.cs +++ /dev/null @@ -1,70 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.Common -{ - /// - /// Describes a package vendor - /// - public sealed class PackageVendor : ItemWithIDAndDisplay, IEquatable - { - public PackageVendor (string id, string display) : base (id, display) - { - } - - /// - /// Determines whether the specified is equal to the - /// current . - /// - /// The to compare with the current . - /// true if the specified is equal to the - /// current ; otherwise, false. - public bool Equals (PackageVendor other) - { - if (other == null) - return false; - - if (!ReferenceEquals (this, other)) - return false; - - if (!string.Equals (ID, other.ID, StringComparison.Ordinal)) - return false; - - return string.Equals (Display, other.Display, StringComparison.Ordinal); - } - - /// - /// Determines whether the specified is equal to the current . - /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. - public override bool Equals (object obj) - { - return Equals (obj as PackageVendor); - } - - /// - /// Serves as a hash function for a object. - /// - /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table. - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - if (ID != null) - hashCode = hashCode.XorWith (ID.GetHashCode ()); - if (Display != null) - hashCode = hashCode.XorWith (Display.GetHashCode ()); - - return hashCode; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Platform.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Platform.cs deleted file mode 100644 index 208a3645a5e..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Common/Platform.cs +++ /dev/null @@ -1,56 +0,0 @@ -#nullable enable - -// -// Platform.cs -// -// Author: -// Vsevolod Kukol -// -// Copyright (c) 2017, Microsoft, Inc -// - -using System; -using System.IO; -using System.Runtime.InteropServices; - -namespace Xamarin.Installer.AndroidSDK.Manager -{ - public static class Platform - { - public readonly static bool IsWindows; - public readonly static bool IsMac; - public readonly static bool IsLinux; - public static Version OSVersion { get; private set; } - - static Platform () - { - IsWindows = Path.DirectorySeparatorChar == '\\'; - IsMac = !IsWindows && IsRunningOnMac (); - IsLinux = !IsMac && !IsWindows; - OSVersion = Environment.OSVersion.Version; - } - - [DllImport ("libc")] - static extern int uname (IntPtr buf); - - //From Managed.Windows.Forms/XplatUI - static bool IsRunningOnMac () - { - IntPtr buf = IntPtr.Zero; - try { - buf = Marshal.AllocHGlobal (8192); - // This is a hacktastic way of getting sysname from uname () - if (uname (buf) == 0) { - string? os = Marshal.PtrToStringAnsi (buf); - if (os == "Darwin") - return true; - } - } catch { - } finally { - if (buf != IntPtr.Zero) - Marshal.FreeHGlobal (buf); - } - return false; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/DirectorySizeMonitoringTimer.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/DirectorySizeMonitoringTimer.cs deleted file mode 100644 index f0d334ecba7..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/DirectorySizeMonitoringTimer.cs +++ /dev/null @@ -1,156 +0,0 @@ -using ICSharpCode.SharpZipLib.Zip; -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Xamarin.Android.Tools; -using Xamarin.Installer.Common; -using Xamarin.Installer.AndroidSDK.Manager; -using Timer = System.Timers.Timer; - -namespace Xamarin.Installer.AndroidSDK -{ - public class DirectorySizeMonitoringTimer : IDisposable - { - const int MIN_MOVE_PROGRESS_SPLIT = 10, MAX_MOVE_PROGRESS_SPLIT = 50; - const int SMALL_NUMBER_OF_FILES = 1, BIG_NUMBER_OF_FILES = 10000; - - Timer timer; - float maxProgress, targetMaxProgress; - Action progressUpdateAction; - bool disposed; - - public DirectorySizeMonitoringTimer (string targetDirectoryPath, string dirToCompareWith, Action progressUpdateAction, - float remapFrom = 0f, float remapTo = 100f, double checkInterval = 500d) - { - this.progressUpdateAction = progressUpdateAction; - maxProgress = -1f; - targetMaxProgress = remapTo; - - progressUpdateAction?.Invoke (remapFrom); - - if (!Platform.IsMac) - return; - - ulong? totalExpectedSize = null; - - timer = new Timer { Interval = checkInterval, AutoReset = false }; - timer.Elapsed += async (_, __) => { - if (disposed) - return; - - if (!totalExpectedSize.HasValue) - totalExpectedSize = await GetDirectorySizeAsync (dirToCompareWith); - - if (disposed) - return; - - var size = await GetDirectorySizeAsync (targetDirectoryPath); - if (size > totalExpectedSize.Value) - size = totalExpectedSize.Value; - - if (disposed) - return; - - float progress = (float) Remap (size * 100f / totalExpectedSize.Value, 0f, 100f, remapFrom, remapTo); - if (progress > maxProgress) { - // Logger.Debug ($"[DirectorySizeMonitoringTimer] size: {size} / totalExpectedSize: {totalExpectedSize} --> {progress}"); - progressUpdateAction.Invoke (progress); - maxProgress = progress; - } - - if (!disposed) - timer.Start(); - }; - timer.Start (); - } - - public void Dispose () - { - disposed = true; - //Logger.Debug ($"DirectorySizeMonitoringTimer disposing"); - timer?.Stop (); - timer?.Dispose (); - - if (maxProgress < targetMaxProgress) - progressUpdateAction?.Invoke (targetMaxProgress); - - progressUpdateAction = null; - } - - async Task GetDirectorySizeAsync (string directory) - { - if (!Platform.IsMac) - return 0; - - var result = 0uL; - var duCommand = "/usr/bin/du"; - var process = ProcessUtils.CreateProcessStartInfo (duCommand, "-sk", directory); - string sizeOutput = null; - try { - using (var output = new StringWriter ()) - using (var error = new StringWriter ()) { - int exitCode = await ProcessUtils.StartProcess (process, output, error, CancellationToken.None); - if (exitCode != 0) - throw new InvalidOperationException ($"{duCommand} exited with code {exitCode}: {error}"); - sizeOutput = output.ToString (); - } - } catch (Exception ex) { - if (ex?.Message?.Contains ("No such file or directory") == true) { - Logger.Debug ($"[DirectorySizeMonitoringTimer] WARN! Dir \"{directory}\" was removed before \"/usr/bin/du\" could calculate its size"); - } else { - Logger.Warning ($"[DirectorySizeMonitoringTimer] ProcessUtils.StartProcess failed to execute {duCommand}.\n{ex}"); - } - } - - if (!String.IsNullOrEmpty (sizeOutput)) { - sizeOutput = sizeOutput.Replace (directory, string.Empty).Trim (); - if (ulong.TryParse (sizeOutput, out ulong parsed)) { - // "k" gives size in KBytes - result = parsed * 1024; - } - } - return result; - } - - public static double Remap (double value, double from1, double to1, double from2, double to2) - { - var mapping = (value - from1) / (to1 - from1) * (to2 - from2) + from2; - if (mapping < from2) - mapping = from2; - if (mapping > to2) - mapping = to2; - return mapping; - } - - public static ulong CalculateTotalSize (ZipFile zipFile) - { - ulong totalSize = 0; - foreach (ZipEntry entry in zipFile) - totalSize += (ulong) entry.Size; - Logger.Debug ($"[DirectorySizeMonitoringTimer] ZipFile totalSize: {totalSize}"); - - return totalSize; - } - - /// - /// Move operation will take different time depending on number of files in an archive - /// so we split the 100% installation progress according these values (unzip + move = 100%) - /// - /// The path to the archive file. - /// Amount of percents for the Move part of the installation - public static int CalculateMoveProgressSplit (string archivePath) - { - ZipFile zip = null; - long filesCount; - try { - zip = new ZipFile (archivePath); - filesCount = zip.Count; - } finally { - zip?.Close (); - } - - return (int) Remap (filesCount, SMALL_NUMBER_OF_FILES, BIG_NUMBER_OF_FILES, MIN_MOVE_PROGRESS_SPLIT, MAX_MOVE_PROGRESS_SPLIT); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IAndroidComponent.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IAndroidComponent.cs deleted file mode 100644 index 4c9f17c80c2..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IAndroidComponent.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.AndroidSDK.GoogleV2; -using Xamarin.Installer.AndroidSDK.Xamarin; - -namespace Xamarin.Installer.AndroidSDK -{ - partial class Extensions - { - internal static IAndroidComponent Clone (this IAndroidComponent component) - { - if (component == null) - return null; - - var rp = component as RemotePackage; - if (rp != null) - return RemotePackage.Clone (rp); - - var xp = component as XamarinPackage; - if (xp != null) - return XamarinPackage.Clone (xp); - - throw new InvalidOperationException ($"Unknown component type {component.GetType ()}"); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IListOfIAndroidComponent.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IListOfIAndroidComponent.cs deleted file mode 100644 index 38994109364..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IListOfIAndroidComponent.cs +++ /dev/null @@ -1,266 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// Extensions to make it easier to select components from a full component set. - /// - public static class PublicExtensions - { - /// - /// Checks whether any components in the passed set are outdated. - /// - /// true, if outdated components were found, false otherwise. - /// Components. - public static bool AnyOutdated (this IList components) - { - return components?.Any (c => c != null && c.NeedsUpdate) ?? false; - } - - /// - /// Checks whether any components in the set aren't preset on the system - /// - /// true, if there are any missing components, false otherwise. - /// Components. - public static bool AnyNotInstalled (this IList components) - { - return components?.Any (c => c != null && !c.Present) ?? false; - } - - /// - /// Returns a list of all outdated or missing components from the passed set/ - /// - /// The outdated or missing components. - /// Components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllOutdatedOrMissing (this IList components, Func shouldInclude = null) - { - var ret = new List (); - ret.AddRange (components.AllOutdated (shouldInclude)); - ret.AddRange (components.AllNotInstalled (shouldInclude: shouldInclude)); - - return ret; - } - - /// - /// Gets all outdated components from the passed set. The returned list contains outdated components from all - /// channels. - /// - /// List of all the outdated components - /// Aource list of components - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllOutdated (this IList components, Func shouldInclude = null) - { - return components?.Where (c => c != null && c.Present && c.NeedsUpdate && (shouldInclude == null || shouldInclude (c)))?.ToList (); - } - - /// - /// Gets all installed components from the passed set. The returned list contains components from all channels - /// - /// List of all installed components - /// Source list of components - /// If set to true include outdated components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllInstalled (this IList components, bool includeOutdated = true, Func shouldInclude = null) - { - return components?.Where (c => c != null && c.Present && (includeOutdated || !c.NeedsUpdate) && (shouldInclude == null || shouldInclude(c)))?.ToList (); - } - - /// - /// Gets all components that aren't installed from the passed set. The returned list contains components from all channels - /// - /// List of or components that aren't installed - /// Source list of components - /// If set to true include obsolete components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllNotInstalled (this IList components, bool includeObsolete = false, Func shouldInclude = null) - { - return components?.Where (c => c != null && !c.Present && (includeObsolete || !c.Obsolete) && (shouldInclude == null || shouldInclude(c)))?.ToList (); - } - - /// - /// Gets all the components of the specified type from the passed set. The returned list contains components from all channels - /// - /// List of components of the specified type - /// Source list of components - /// Component type - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllOfType (this IList components, AndroidComponentType type, Func shouldInclude = null) - { - return GetAllOfType (components, type, shouldInclude)?.ToList (); - } - - /// - /// Gets all the platform components from the passed set. - /// - /// List of platform components - /// Source list of components - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllPlatforms (this IList components, Func shouldInclude = null) - { - return GetAllOfType (components, AndroidComponentType.Platform, shouldInclude)?.ToList (); - } - - /// - /// Gets all the system image components from the passed set. The returned list contains components from all channels - /// - /// List of system image components. - /// Source list of components - /// Select only components that use this ABI - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllSystemImages (this IList components, AndroidSystemImageAbi forABI = AndroidSystemImageAbi.Any, Func shouldInclude = null) - { - return GetAllOfType (components, AndroidComponentType.SystemImage, shouldInclude)?.Where (c => forABI == AndroidSystemImageAbi.Any || (c.Info as AndroidComponentInfoSystemImage).Abi == forABI)?.ToList (); - } - - /// - /// Gets all the components that use the specified API level (platform). The returned list contains components from all channels - /// - /// List of components using the specified API level - /// Source list of components - /// API level to match. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllApiLevel (this IList components, string apiLevel = null, Func shouldInclude = null) - { - return GetAllApiLevel (components, apiLevel, shouldInclude)?.ToList (); - } - - /// - /// Gets all the components with a matching path. The returned list contains components from all channels - /// - /// List of components with a matching path - /// Source list of components - /// Path. - /// Minimum revision of the components. - /// An optional delegate which decides whether or not to include the component passed to it - /// If true it will check whether the component path starts with the specified one. - public static IList AllWithPath (this IListcomponents, string path, AndroidRevision minimumRevision = null, Func shouldInclude = null, bool matchPathStartOnly = false) - { - if (String.IsNullOrEmpty (path)) - return null; - - return components?.Where (c => c != null && - !String.IsNullOrEmpty (c.Path) && - PathMatches (c) && - (minimumRevision == null || c.Revision >= minimumRevision) && - (shouldInclude == null || shouldInclude (c)))?.ToList (); - - bool PathMatches (IAndroidComponent c) - { - if (c == null || c.Path == null) - return false; - - if (matchPathStartOnly) - return c.Path.StartsWith (path, StringComparison.Ordinal); - return string.Equals (c.Path, path, StringComparison.Ordinal); - } - } - - /// - /// Get all of the Build Tools components. The returned list contains components from all channels - /// - /// List of the Build Tools components - /// Source list of components - /// Minimum revision of the components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllBuildTools (this IList components, AndroidRevision minimumRevision = null, Func shouldInclude = null) - { - return components.AllWithPath (Constants.ComponentPaths.BuildTools, minimumRevision, shouldInclude, true); - } - - /// - /// Get all of the Tools components. The returned list contains components from all channels - /// - /// List of the Tools components - /// Source list of components - /// Minimum revision of the components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllTools (this IList components, AndroidRevision minimumRevision = null, Func shouldInclude = null) - { - return components.AllWithPath (Constants.ComponentPaths.Tools, minimumRevision, shouldInclude, true); - } - - /// - /// Get all of the Platform Tools components. The returned list contains components from all channels - /// - /// List of the Platform Tools components - /// Source list of components - /// Minimum revision of the components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllPlatformTools(this IList components, AndroidRevision minimumRevision = null, Func shouldInclude = null) - { - return components.AllWithPath (Constants.ComponentPaths.PlatformTools, minimumRevision, shouldInclude); - } - - /// - /// Get all of the Emulator components. The returned list contains components from all channels - /// - /// List of the Emulator components - /// Source list of components - /// Minimum revision of the components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllEmulators (this IList components, AndroidRevision minimumRevision = null, Func shouldInclude = null) - { - return components.AllWithPath (Constants.ComponentPaths.Emulator, minimumRevision, shouldInclude); - } - - /// - /// Get all of the CMake components. The returned list contains components from all channels - /// - /// List of the CMake components - /// Source list of components - /// Minimum revision of the components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllCMake (this IList components, AndroidRevision minimumRevision = null, Func shouldInclude = null) - { - return components.AllWithPath (Constants.ComponentPaths.CMake, minimumRevision, shouldInclude, true); - } - - /// - /// Get all of the LLDB components. The returned list contains components from all channels - /// - /// List of the LLDB components - /// Source list of components - /// Minimum revision of the components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllLLDB (this IList components, AndroidRevision minimumRevision = null, Func shouldInclude = null) - { - return components.AllWithPath (Constants.ComponentPaths.LLDB, minimumRevision, shouldInclude, true); - } - - /// - /// Get all of the NDK components. The returned list contains components from all channels - /// - /// List of the Emulator components - /// Source list of components - /// Minimum revision of the components. - /// An optional delegate which decides whether or not to include the component passed to it - public static IList AllNDK (this IList components, AndroidRevision minimumRevision = null, Func shouldInclude = null) - { - return components.AllWithPath (Constants.ComponentPaths.NDK, minimumRevision, shouldInclude); - } - - public static IList AllAddons (this IList components, AndroidRevision minimumRevision = null, Func shouldInclude = null) - { - return GetAllOfType (components, AndroidComponentType.Addon, shouldInclude)?.ToList (); - } - - static IEnumerable GetAllApiLevel (IList components, string apiLevel, Func shouldInclude) - { - bool haveApiLevel = !String.IsNullOrEmpty (apiLevel); - return components?.OfType ()?. - Where (c => c != null && (!haveApiLevel || string.Equals(c.ApiLevel, apiLevel, StringComparison.OrdinalIgnoreCase)))?. - Select (c => c as IAndroidComponent). - Where (c => shouldInclude == null || shouldInclude(c)); - } - - static IEnumerable GetAllOfType (IList components, AndroidComponentType type, Func shouldInclude) - { - return components?.Where (c => c != null && c.ComponentType == type && (shouldInclude == null || shouldInclude(c))); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IListOfT.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IListOfT.cs deleted file mode 100644 index 46af9a6d574..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IListOfT.cs +++ /dev/null @@ -1,35 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; - -namespace Xamarin.Installer.AndroidSDK -{ - static partial class Extensions - { - public static bool AreEqual (this IList one, IList two) - { - if (one == null) - return two == null; - if (two == null) - return false; - - if (one.Count != two.Count) - return false; - - // Order of elements shouldn't matter I think - foreach (T item in one) { - if (!two.Contains (item)) - return false; - } - - return true; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IXmlLineInfo.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IXmlLineInfo.cs deleted file mode 100644 index bfa08892c0d..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.IXmlLineInfo.cs +++ /dev/null @@ -1,26 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Xml; - -namespace Xamarin.Installer.AndroidSDK -{ - static partial class Extensions - { - public static string AsString (this IXmlLineInfo info, string openBracket = "[", string closeBracket = "]") - { - if (info == null || (info.LineNumber < 0 && info.LinePosition < 0)) - return String.Empty; - string open = openBracket ?? String.Empty; - string close = closeBracket ?? String.Empty; - - return $"{open}{info.LineNumber}:{info.LinePosition}{close}"; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.Int32.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.Int32.cs deleted file mode 100644 index c1b79af8572..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.Int32.cs +++ /dev/null @@ -1,29 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK -{ - static partial class Extensions - { - public static int XorWith (this int value, int? maybeValue) - { - if (!maybeValue.HasValue) - return value; - - return XorWith (value, maybeValue.Value); - } - - public static int XorWith (this int value, int otherValue) - { - return value ^ otherValue; - - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.Properties.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.Properties.cs deleted file mode 100644 index 267ac86a8b8..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.Properties.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Xamarin.Installer.AndroidSDK -{ - static partial class Extensions - { - public static bool GetProperty (this IDictionary props, string name, out T result) - { - result = default (T); - if (props == null) - return false; - if (!props.TryGetValue (name, out string value)) - return false; - if (value != null) - value = value.Trim (); - if (String.IsNullOrEmpty (value)) - return false; - - if (typeof (T) == typeof (string)) { - result = (T)((object)value); - return true; - } - - try { - result = (T)Convert.ChangeType (value, typeof (T)); - } catch { - // ignore - return false; - } - return true; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.String.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.String.cs deleted file mode 100644 index cfc4713a904..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.String.cs +++ /dev/null @@ -1,73 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK -{ - static partial class Extensions - { - public static uint AsUInt (this string s, bool throwOnError = false) - { - if (String.IsNullOrEmpty (s)) - return 0; - - uint ret; - if (UInt32.TryParse (s, out ret)) - return ret; - - if (throwOnError) - throw new InvalidOperationException ($"Unable to convert string '{s}' to an unsigned integer"); - return 0; - } - - public static ulong AsULong (this string s, bool throwOnError = false) - { - if (String.IsNullOrEmpty (s)) - return 0; - - ulong ret; - if (UInt64.TryParse (s, out ret)) - return ret; - - if (throwOnError) - throw new InvalidOperationException ($"Unable to convert string '{s}' to an unsigned long integer"); - return 0; - } - - public static bool AsBool (this string s, bool throwOnError = false) - { - if (String.IsNullOrEmpty (s)) - return false; - - bool ret; - if (Boolean.TryParse (s, out ret)) - return ret; - - if (throwOnError) - throw new InvalidOperationException ($"Unable to convert string '{s}' to boolean"); - - return false; - } - - public static Uri AsUri (this string s, bool throwOnError = false) - { - if (String.IsNullOrEmpty (s)) - return null; - - Uri ret; - if (Uri.TryCreate (s, UriKind.RelativeOrAbsolute, out ret)) - return ret; - - if (throwOnError) - throw new InvalidOperationException ($"Unable to parse string '{s}' as a valid URI"); - - return null; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.XElement.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.XElement.cs deleted file mode 100644 index ff64a9e22d8..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.XElement.cs +++ /dev/null @@ -1,109 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml; -using System.Xml.Linq; - -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - public static partial class Extensions - { - public static void GetLineInfo (this XElement e, out int line, out int column) - { - IXmlLineInfo linfo = e.GetLineInfo (); - if (linfo == null || !linfo.HasLineInfo ()) { - line = column = -1; - return; - } - line = linfo.LineNumber; - column = linfo.LinePosition; - } - - public static IXmlLineInfo GetLineInfo (this XElement e) - { - return e as IXmlLineInfo; - } - - public static string GetLocation (this XElement e, Uri documentUrl = null) - { - if (e == null) - return String.Empty; - - if (documentUrl == null) - return e.GetLineInfo ().AsString ("(", ")"); - - return $"({documentUrl} {e.GetLineInfo ().AsString ()}"; - } - - public static string GetChildElementValue (this XElement element, string childName) - { - if (element == null) - return String.Empty; - - XElement child = element.Elements (childName)?.FirstOrDefault (); - return child?.Value ?? String.Empty; - } - - public static string GetAttributeValue (this XElement e, string name, bool required = true, Uri documentUrl = null) - { - XAttribute ret = e.GetAttribute (name); - if (ret == null) { - if (required) - throw new InvalidOperationException ($"Required attribute '{name}' missing for element {e?.Name} at {e.GetLocation (documentUrl)}"); - return String.Empty; - } - - return ret.Value; - } - - public static XAttribute GetAttribute (this XElement e, string name) - { - return e?.Attribute (name); - } - - public static XAttribute GetAttribute (this XElement e, XNamespace ns, string name) - { - return e?.Attribute (ns + name); - } - - public static string GetElementValue (this XElement e) - { - return e?.Value?.Trim (); - } - - public static void GetNamespaces (this XElement root, Uri docURL, ref Dictionary namespaces) - { - if (root == null || !root.HasAttributes) - return; - - foreach (XAttribute attr in root.Attributes ()) - GetNamespace (root, attr, docURL, ref namespaces); - } - - static void GetNamespace (XElement element, XAttribute attr, Uri docURL, ref Dictionary namespaces) - { - if (!attr.IsNamespaceDeclaration) - return; - - if (namespaces == null) - namespaces = new Dictionary (StringComparer.Ordinal); - - if (namespaces.ContainsKey (attr.Name.LocalName)) { - if (namespaces[attr.Name.LocalName] != attr.Value) - Logger.Warning ($"Element '{element.Name.GetFullName ()}' has a duplicate attribute '{attr.Name.GetFullName ()}' in document '{docURL}'. New value will override the old one"); - namespaces[attr.Name.LocalName] = attr.Value; - } else - namespaces.Add (attr.Name.LocalName, attr.Value); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.XName.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.XName.cs deleted file mode 100644 index 742145b65b2..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Extensions.XName.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK -{ - static partial class Extensions - { - public static string GetFullName (this XName name) - { - if (name == null) - return String.Empty; - - if (!String.IsNullOrEmpty (name.NamespaceName)) - return $"{name.NamespaceName}:{name.LocalName}"; - - return name.LocalName; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/AddonSite.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/AddonSite.cs deleted file mode 100644 index 3827dfa4bf0..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/AddonSite.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2 -{ - public class AddonSite - { - public AddonSiteType Type { get; } - public string DisplayName { get; } - public Uri Url { get; } - - public AddonSite (AddonSiteType type, string displayName, Uri url) - { - if (url == null) - throw new ArgumentNullException (nameof (url)); - DisplayName = displayName ?? "Unnamed"; - Url = url; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/AddonSiteType.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/AddonSiteType.cs deleted file mode 100644 index f135a8cc1b2..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/AddonSiteType.cs +++ /dev/null @@ -1,19 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2 -{ - public enum AddonSiteType - { - Unknown, - SystemImage, - Addon - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Extensions.IParserErrorHandler.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Extensions.IParserErrorHandler.cs deleted file mode 100644 index 8b708d2256f..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Extensions.IParserErrorHandler.cs +++ /dev/null @@ -1,135 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2 -{ - public static partial class Extensions - { - public static void Fatal (this IParserErrorHandler handler, string message) - { - handler.Fatal (null, null, message); - } - - public static void Fatal (this IParserErrorHandler handler, Uri url, string message) - { - handler.Fatal (url, null, message); - } - - public static void Fatal (this IParserErrorHandler handler, XElement element, string message, bool addLocationInfo = true) - { - handler.Fatal (null, element, message); - } - - public static void Fatal (this IParserErrorHandler handler, Uri documentUrl, XElement element, string message, bool addLocationInfo = true) - { - if (handler == null) - return; - - handler.OnFatalError (documentUrl, element, $"{message}{RenderLocation (documentUrl, element, addLocationInfo)}"); - } - - public static void Error (this IParserErrorHandler handler, string message) - { - handler.Error (null, null, message); - } - - public static void Error (this IParserErrorHandler handler, Uri url, string message) - { - handler.Error (url, null, message); - } - - public static void Error (this IParserErrorHandler handler, XElement element, string message, bool addLocationInfo = true) - { - handler.Error (null, element, message, addLocationInfo); - } - - public static void Error (this IParserErrorHandler handler, Uri documentUrl, XElement element, string message, bool addLocationInfo = true) - { - ReportRecoverableError (handler, ParserErrorLevel.Error, documentUrl, element, message, addLocationInfo); - } - - public static void Warning (this IParserErrorHandler handler, string message) - { - handler.Warning (null, null, message); - } - - public static void Warning (this IParserErrorHandler handler, Uri url, string message) - { - handler.Warning (url, null, message); - } - - public static void Warning (this IParserErrorHandler handler, XElement element, string message, bool addLocationInfo = true) - { - handler.Warning (null, element, message, addLocationInfo); - } - - public static void Warning (this IParserErrorHandler handler, Uri documentUrl, XElement element, string message, bool addLocationInfo = true) - { - ReportRecoverableError (handler, ParserErrorLevel.Warning, documentUrl, element, message, addLocationInfo); - } - - public static void Info (this IParserErrorHandler handler, string message) - { - handler.Info (null, null, message); - } - - public static void Info (this IParserErrorHandler handler, Uri url, string message) - { - handler.Info (url, null, message); - } - - public static void Info (this IParserErrorHandler handler, XElement element, string message, bool addLocationInfo = true) - { - handler.Info (null, element, message, addLocationInfo); - } - - public static void Info (this IParserErrorHandler handler, Uri documentUrl, XElement element, string message, bool addLocationInfo = true) - { - ReportRecoverableError (handler, ParserErrorLevel.Info, documentUrl, element, message, addLocationInfo); - } - - public static void Debug (this IParserErrorHandler handler, string message) - { - handler.Debug (null, null, message); - } - - public static void Debug (this IParserErrorHandler handler, Uri url, string message) - { - handler.Debug (url, null, message); - } - - public static void Debug (this IParserErrorHandler handler, XElement element, string message, bool addLocationInfo = true) - { - handler.Debug (null, element, message, addLocationInfo); - } - - public static void Debug (this IParserErrorHandler handler, Uri documentUrl, XElement element, string message, bool addLocationInfo = true) - { - ReportRecoverableError (handler, ParserErrorLevel.Debug, documentUrl, element, message, addLocationInfo); - } - - static void ReportRecoverableError (IParserErrorHandler handler, ParserErrorLevel level, Uri documentUrl, XElement element, string message, bool addLocationInfo = true) - { - if (handler == null) - return; - - handler.OnRecoverableError (level, documentUrl, element, $"{message}{RenderLocation (documentUrl, element, addLocationInfo)}"); - } - - static string RenderLocation (Uri documentUrl, XElement element, bool addLocationInfo) - { - if (!addLocationInfo) - return String.Empty; - - return $" {element.GetLocation (documentUrl)}"; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/GoogleV2Repository.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/GoogleV2Repository.cs deleted file mode 100644 index 46d5a85ccf3..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/GoogleV2Repository.cs +++ /dev/null @@ -1,314 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.AndroidSDK.GoogleV2.Parsing; -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2 -{ - public class GoogleV2Repository : Repository - { - static readonly Uri DefaultRepositoryBaseURL = new Uri ("https://dl.google.com/android/repository/"); - static readonly Uri DefaultManifestURL = new Uri (DefaultRepositoryBaseURL, $"repository2-3.xml"); - static readonly Uri DefaultAddonsListURL = new Uri (DefaultRepositoryBaseURL, $"addons_list-5.xml"); - static readonly Regex MANIFEST_FILE_NAME_SANITIZER_REGEX = new Regex ("[-,\\s]+"); - - ParserContext parserContext; - - List repoParts; - - IParserErrorHandler errorHandler; - - public Uri RepositoryBaseURL { get; private set; } - public Uri AddonsListURL { get; private set; } - - public GoogleV2Repository (IParserErrorHandler errorHandler, Uri manifestURL = null, Uri addonsListURL = null, Uri repositoryBaseURL = null, bool cacheManifest = false) - : base ("Google Repository V2", manifestURL ?? DefaultManifestURL) - { - this.errorHandler = errorHandler ?? throw new ArgumentNullException (nameof (errorHandler)); - if (repositoryBaseURL != null) - RepositoryBaseURL = repositoryBaseURL; - else if (manifestURL == null) - RepositoryBaseURL = DefaultRepositoryBaseURL; - else - RepositoryBaseURL = Helpers.GetBaseURL (manifestURL); - - AddonsListURL = addonsListURL ?? DefaultAddonsListURL; - - if (cacheManifest) - ManifestCacher = LocalManifestProvider.CreateGoogleManifestProvider (); - } - - public override void Parse () - { - string manifest = LoadManifest (); - if (string.IsNullOrEmpty (manifest)) { - Logger.Warning ($"Android manifest should not be empty! Manifest URL: {ManifestURL}"); - // todo: should we throw here? - return; - } - - string addonManifest = null; - bool haveAddons = false; - try { - haveAddons = CommonUtilities.Helpers.DownloadToString (AddonsListURL, out addonManifest); - - if (haveAddons && addonManifest != null) - ManifestCacher?.SaveManifest (addonManifest, ManifestNameToFileName (AddonsListURL.Segments.Last ())); - } catch (Exception ex) { - Logger.Error ($"Failed to download addons manifest {AddonsListURL}. Ex: {ex}"); - } - - if (addonManifest == null) { - Logger.Info ("Trying to load cached addon manifest..."); - - addonManifest = ManifestCacher?.GetManifest (ManifestNameToFileName (AddonsListURL.Segments.Last ())); - if (addonManifest != null) - haveAddons = true; - } - try { - parserContext = new ParserContext ( - errorHandler, - RepositoryBaseURL, - ManifestURL, new MemoryStream (Encoding.UTF8.GetBytes (manifest)), - AddonsListURL, haveAddons ? new MemoryStream (Encoding.UTF8.GetBytes (addonManifest)) : null - ); - ParseInternal (); - DefaultChannel = GetChannel ("channel-0"); - Parsed = true; - } finally { - parserContext?.Dispose (); - parserContext = null; - } - } - - void ParseInternal () - { - Dictionary namespaces = null; - repoParts = new List (); - - Components?.Clear (); - if (!ParseRepository (parserContext.RepositoryManifest, ManifestURL, ref namespaces)) { - Logger.Error ("Unable to parse repository {0} at URL `{1}`.", parserContext.RepositoryManifest, ManifestURL); - return; - } - if (parserContext.AddonsListManifest != null) - ParseAddons (parserContext.AddonsListManifest, parserContext.AddonsListManifestURL, ref namespaces); - - Namespaces = namespaces; - parserContext.ErrorHandler.Debug ("Namespaces:"); - foreach (var kvp in namespaces) { - parserContext.ErrorHandler.Debug ($" {kvp.Key}:{kvp.Value}"); - } - - Dictionary licenses = null; - Dictionary channels = null; - int duplicateChannelIdCounter = 0; - int duplicateLicenseIdCounter = 0; - - foreach (RepositoryParser rp in repoParts) { - if (rp == null) - continue; - - MergeItems (rp.Channels, ref channels, ref duplicateChannelIdCounter, (string newID, Channel ch) => { - UpdateIDs (rp.Packages, ch, (RemotePackage p) => p.ChannelID, (RemotePackage p) => p.ChannelID = newID); - }); - - MergeItems (rp.Licenses, ref licenses, ref duplicateLicenseIdCounter, (string newID, License lic) => { - UpdateIDs (rp.Packages, lic, (RemotePackage p) => p.LicenseID, (RemotePackage p) => p.LicenseID = newID); - }); - - AddComponents (rp); - } - - if (Components != null) - parserContext.ErrorHandler.Debug ($"{Name}: found {Components.Count} packages loaded from {repoParts.Count} repositories"); - - if (licenses != null && licenses.Count > 0) { - parserContext.ErrorHandler.Debug ($"{Name}: found {licenses.Count} unique licenses"); - CopyDictionary (licenses, Licenses); - licenses.Clear (); - licenses = null; - } - - if (channels != null && channels.Count > 0) { - parserContext.ErrorHandler.Debug ($"{Name}: found {channels.Count} unique channels"); - CopyDictionary (channels, Channels); - channels.Clear (); - channels = null; - } - } - - void AddComponents (RepositoryParser rp) - { - if (rp.Packages == null || rp.Packages.Count == 0) - return; - - foreach (RemotePackage package in rp.Packages) { - if (package == null) - continue; - - Components.Add (package); - } - } - - void UpdateIDs (List packages, T item, Func getID, Action setID) where T : ItemWithID - { - if (packages == null || packages.Count == 0) - return; - - foreach (RemotePackage rp in packages) { - if (rp == null || !string.Equals (getID (rp), item.ID, StringComparison.Ordinal)) - continue; - setID (rp); - } - } - - void MergeItems (Dictionary sourceDict, ref Dictionary items, ref int duplicateIdCounter, Action updateID) where T : ItemWithID - { - if (sourceDict == null || sourceDict.Count == 0) - return; - - foreach (KeyValuePair kvp in sourceDict) { - if (kvp.Value == null) - continue; - MergeItemWithID (kvp.Value, ref duplicateIdCounter, ref items, updateID); - } - } - - void MergeItemWithID (T item, ref int duplicateIdCounter, ref Dictionary items, Action updateID) where T : ItemWithID - { - if (item == null) - return; - - if (items == null) - items = new Dictionary (StringComparer.Ordinal); - - if (items.ContainsValue (item)) { - if (items.ContainsKey (item.ID)) - return; - - // We have an identical item but with a different dictionary key, we must update the ID - KeyValuePair kvp = items.FirstOrDefault ((KeyValuePair i) => item == i.Value); - if (kvp.Value == null) - return; - updateID (kvp.Key, kvp.Value); - return; - } - - string itemID; - if (items.ContainsKey (item.ID)) { - // We have an item with identical ID but different contents - duplicateIdCounter++; - itemID = $"{item.ID}_{duplicateIdCounter}"; - } else - itemID = item.ID; - items.Add (itemID, item); - } - - bool ParseRepository (Stream manifest, Uri url, ref Dictionary namespaces) - { - XDocument doc = LoadManifest (parserContext, manifest, url, ref namespaces); - if (doc == null) { - return false; - } - - var repoParser = new RepositoryParser (this, parserContext, doc.Root, namespaces); - repoParser.Parse (); - repoParts.Add (repoParser); - return true; - } - - void ParseAddons (Stream manifest, Uri url, ref Dictionary namespaces) - { - XDocument doc = LoadManifest (parserContext, manifest, url, ref namespaces); - if (doc == null) { - return; - } - var addonListParser = new AddonList3Parser (parserContext, doc.Root, namespaces); - addonListParser.Parse (); - - if (addonListParser.Sites == null || addonListParser.Sites.Count == 0) { - parserContext.ErrorHandler.Error (parserContext.CurrentManifestURL, doc.Root, $"No addon or system image sites found at URL '{url}'"); - return; - } - - foreach (AddonSite site in addonListParser.Sites) { - string addonManifest = null; - bool gotAddonManifest = false; - - try { - gotAddonManifest = CommonUtilities.Helpers.DownloadToString (site.Url, out addonManifest); - if (gotAddonManifest && addonManifest != null) - ManifestCacher?.SaveManifest (addonManifest, ManifestNameToFileName (site.DisplayName + '_' + AddonsListURL.Segments.Last ())); - } catch (Exception ex) { - Logger.Error ($"Failed to load local addon manifest: {ex}"); - } - - if (addonManifest == null) { - Logger.Info ("Trying to load cached sites manifest..."); - addonManifest = ManifestCacher?.GetManifest (ManifestNameToFileName (site.DisplayName + '_' + AddonsListURL.Segments.Last ())); - if (addonManifest != null) - gotAddonManifest = true; - } - - if (!gotAddonManifest && addonManifest == null) - continue; - - using (Stream addonManifestContents = new MemoryStream (Encoding.UTF8.GetBytes (addonManifest))) { - if (!ParseRepository (addonManifestContents, site.Url, ref namespaces)) { - Logger.Error ("Unable to parse addon manifest contents"); - addonManifestContents.Position = 0; - Logger.Debug ("{0}", new StreamReader(addonManifestContents).ReadToEnd ()); - } - } - } - } - - string ManifestNameToFileName (string name) - { - return "google_" + MANIFEST_FILE_NAME_SANITIZER_REGEX.Replace (name, "_").ToLower(); - } - - XDocument LoadManifest (ParserContext context, Stream manifest, Uri url, ref Dictionary namespaces) - { - try { - context.CurrentManifestURL = null; - XDocument doc = ParseManifest (GetManifestNameForUrl (url), manifest, LoadOptions.SetLineInfo); - doc.Root.GetNamespaces (url, ref namespaces); - - context.CurrentManifestURL = url; - return doc; - } - catch (Exception) { - // Error message logged by ParseManifest() - return null; - } - } - - string GetManifestNameForUrl (Uri url) - { - var segments = url.Segments; - var result = "GoogleAndroidManifest"; - if (segments.Length > 0) { - var lastUrlSegment = segments[segments.Length - 1]; - return result += $"-{lastUrlSegment.Replace (".xml", "")}"; - } - return result; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/IParserErrorHandler.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/IParserErrorHandler.cs deleted file mode 100644 index 879f4606c99..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/IParserErrorHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2 -{ - public interface IParserErrorHandler - { - void OnRecoverableError (ParserErrorLevel recommendedLevel, Uri url, XElement element, string message); - void OnFatalError (Uri url, XElement element, string message); - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/AddonList3Parser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/AddonList3Parser.cs deleted file mode 100644 index f44c5ad583a..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/AddonList3Parser.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - public class AddonList3Parser : ElementParser - { - List sites; - - public IList Sites { get; private set; } - - public AddonList3Parser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - IgnoreNamespaceAttributes = true; - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"site", ParseChildElement_Site} - }; - } - - protected override void Parsed () - { - base.Parsed (); - Sites = sites; - } - - void ParseChildElement_Site (XElement element) - { - var asp = new AddonSiteParser (Context, element, Namespaces); - asp.Parse (); - - if (asp.Type == AddonSiteType.Unknown) - return; - - if (sites == null) - sites = new List (); - - sites.Add (new AddonSite (asp.Type, asp.DisplayName, asp.Url)); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/AddonSiteParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/AddonSiteParser.cs deleted file mode 100644 index 9f0cb9e9688..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/AddonSiteParser.cs +++ /dev/null @@ -1,90 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class AddonSiteParser : ElementParser - { - static readonly Dictionary siteTypeMap = new Dictionary (StringComparer.Ordinal) { - {"sdk:sysImgSiteType", AddonSiteType.SystemImage}, - {"sdk:addonSiteType", AddonSiteType.Addon} - }; - - public AddonSiteType Type { get; private set; } = AddonSiteType.Unknown; - public string DisplayName { get; private set; } = "Unnamed"; - public Uri Url { get; private set; } - - public AddonSiteParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return new Dictionary> (StringComparer.Ordinal) { - {GetAttributeName ("xsi", "type"), ParseAttribute_Type} - }; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"displayName", ParseChildElement_DisplayName}, - {"url", ParseChildElement_Url} - }; - } - - void ParseChildElement_DisplayName (XElement element) - { - DisplayName = element.Value ?? "Unnamed"; - } - - void ParseChildElement_Url (XElement element) - { - Uri url; - - if (!Uri.TryCreate (element.Value?.Trim (), UriKind.RelativeOrAbsolute, out url)) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"The '{element.Name.LocalName}' element contains invalid URL: '{element.Value}'"); - return; - } - - Url = EnsureAbsoluteUrl (url); - } - - void ParseAttribute_Type (XAttribute attr) - { - AddonSiteType type; - if (!siteTypeMap.TryGetValue (attr.Value, out type)) { - ErrorHandler.Warning (Context.CurrentManifestURL, Element, $"'xsi:type' attribute with value '{attr.Value}' does not map to a known site type"); - return; - } - - Type = type; - } - - protected override void Parsed () - { - base.Parsed (); - - if (Type == AddonSiteType.Unknown) { - ErrorHandler.Warning (Context.CurrentManifestURL, Element, $"Unknown site type for element '{Element.Name.GetFullName ()}', site will be ignored"); - Url = null; - DisplayName = null; - return; - } - - if (Url == null) { - Type = AddonSiteType.Unknown; - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"Element '{Element.Name.GetFullName ()}' has a valid type but no URL, site will be ignored"); - } - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchiveMetadataExtractor.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchiveMetadataExtractor.cs deleted file mode 100644 index 73dbcf1df74..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchiveMetadataExtractor.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class ArchiveMetadataExtractor - { - public ulong Size { get; } - public string Checksum { get; } - public string ChecksumType { get; } - public Uri Url { get; } - - public ArchiveMetadataExtractor (XElement element, ParserContext parserContext) - { - if (element == null) - throw new ArgumentNullException (nameof (element)); - - if (parserContext == null) - throw new ArgumentNullException (nameof (parserContext)); - - ulong s; - string v = element.GetChildElementValue ("size"); - if (!String.IsNullOrEmpty (v) && UInt64.TryParse (v, out s)) - Size = s; - else - Size = 0; - - XElement checksumElement = element.Elements ("checksum")?.FirstOrDefault (); - if (checksumElement != null) { - Checksum = checksumElement.Value; - ChecksumType = checksumElement.Attribute ("type")?.Value; - } - - Uri url; - v = element.GetChildElementValue ("url"); - if (String.IsNullOrEmpty (v) || !Uri.TryCreate (v, UriKind.RelativeOrAbsolute, out url)) - return; - - if (url.IsAbsoluteUri) - Url = url; - else - Url = new Uri (parserContext.CurrentManifestBaseURL, url); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchiveParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchiveParser.cs deleted file mode 100644 index d713ca1be99..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchiveParser.cs +++ /dev/null @@ -1,95 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class ArchiveParser : ElementParser - { - ulong size; - string checksum; - string checksumType; - Uri url; - string hostOS; - string hostArch; - uint hostBits; - IList patches; - - public Archive Archive { get; private set; } - - public ArchiveParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"complete", ParseChildElement_Complete}, - {"host-os", (XElement element) => hostOS = element.Value}, - {"host-bits", (XElement element) => hostBits = element.Value.AsUInt ()}, - {"host-arch", (XElement element) => { - hostArch = element.GetElementValue(); - if (hostBits != 0) { - hostBits = HostArchToBits(hostArch); - } - }}, - {"patches", ParseChildElement_Patches} - }; - } - - static uint HostArchToBits (string hostArch) - { - switch (hostArch) { - case "aarch64": return 64; - case "x64": return 64; - case "x86": return 32; - } - throw new NotSupportedException ($"Unsupported architecture {hostArch}"); - } - - void ParseChildElement_Patches (XElement element) - { - var ap = new ArchivePatchesParser (Context, element, Namespaces); - ap.Parse (); - patches = ap.Patches; - } - - void ParseChildElement_Complete (XElement element) - { - var ame = new ArchiveMetadataExtractor (element, Context); - size = ame.Size; - checksum = ame.Checksum; - checksumType = ame.ChecksumType; - url = ame.Url; - } - - protected override void Parsed () - { - base.Parsed (); - Archive = new Archive (hostOS) { - Size = size, - Checksum = checksum, - ChecksumType = checksumType, - Url = url, - HostBits = hostBits, - HostArch = hostArch, - Patches = patches - }; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivePatchParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivePatchParser.cs deleted file mode 100644 index e5e3691475a..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivePatchParser.cs +++ /dev/null @@ -1,65 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class ArchivePatchParser : ElementParser - { - AndroidRevision basedOn; - - public ArchivePatch Patch { get; private set; } - - public ArchivePatchParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"based-on", ParseChildElement_BasedOn}, - - // The three elements below are special treatment, done in Parsed() - {"size", (XElement) => {}}, - {"checksum", (XElement) => {}}, - {"url", (XElement) => {}}, - }; - } - - void ParseChildElement_BasedOn (XElement element) - { - var rp = new RevisionParser (Context, element, Namespaces); - rp.Parse (); - basedOn = rp.Revision; - } - - protected override void Parsed () - { - base.Parsed (); - - var ame = new ArchiveMetadataExtractor (Element, Context); - Patch = new ArchivePatch { - BasedOn = basedOn, - Checksum = ame.Checksum, - ChecksumType = ame.ChecksumType, - Size = ame.Size, - Url = ame.Url - }; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivePatchesParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivePatchesParser.cs deleted file mode 100644 index 37612d1fbd8..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivePatchesParser.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class ArchivePatchesParser : ElementParser - { - List patches; - - public IList Patches { get; private set; } - - public ArchivePatchesParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"patch", ParseChildElement_Patch} - }; - } - - void ParseChildElement_Patch (XElement element) - { - var ap = new ArchivePatchParser (Context, element, Namespaces); - ap.Parse (); - if (ap.Patch == null) - return; - - if (patches == null) - patches = new List (); - patches.Add (ap.Patch); - } - - protected override void Parsed () - { - base.Parsed (); - Patches = patches?.AsReadOnly (); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivesParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivesParser.cs deleted file mode 100644 index e66562a9deb..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ArchivesParser.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class ArchivesParser : ElementParser - { - List archives; - - public IList Archives { get; private set; } - - public ArchivesParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"archive", ParseChildElement_Archive} - }; - } - - void ParseChildElement_Archive (XElement element) - { - var ap = new ArchiveParser (Context, element, Namespaces); - ap.Parse (); - if (ap.Archive == null) - return; - - if (archives == null) - archives = new List (); - archives.Add (ap.Archive); - } - - protected override void Parsed () - { - base.Parsed (); - Archives = archives?.AsReadOnly (); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/DependenciesParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/DependenciesParser.cs deleted file mode 100644 index 97ab2f29ed5..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/DependenciesParser.cs +++ /dev/null @@ -1,59 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class DependenciesParser : ElementParser - { - List dependencies; - - public IList Dependencies { get; private set; } - - public DependenciesParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"dependency", ParseChildElement_Dependency} - }; - } - - void ParseChildElement_Dependency (XElement element) - { - var dep = new DependencyParser (Context, element, Namespaces); - dep.Parse (); - - if (dep.Dependency == null) - return; - - if (dependencies == null) - dependencies = new List (); - dependencies.Add (dep.Dependency); - } - - protected override void Parsed () - { - base.Parsed (); - Dependencies = dependencies?.AsReadOnly (); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/DependencyParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/DependencyParser.cs deleted file mode 100644 index e958931f3bc..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/DependencyParser.cs +++ /dev/null @@ -1,62 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class DependencyParser : ElementParser - { - string path; - AndroidRevision minRevision; - - public Dependency Dependency { get; private set; } - - public DependencyParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return new Dictionary> (StringComparer.Ordinal) { - {"path", ParseAttribute_Path} - }; - } - - void ParseAttribute_Path (XAttribute attr) - { - path = attr.Value; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"min-revision", ParseChildElement_MinRevision} - }; - } - - void ParseChildElement_MinRevision (XElement element) - { - var rp = new RevisionParser (Context, element, Namespaces); - rp.Parse (); - minRevision = rp.Revision; - } - - protected override void Parsed () - { - base.Parsed (); - if (String.IsNullOrEmpty (path)) - return; - Dependency = new Dependency (path, minRevision); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ElementParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ElementParser.cs deleted file mode 100644 index e253716f853..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ElementParser.cs +++ /dev/null @@ -1,133 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - public abstract class ElementParser - { - protected XElement Element { get; } - protected ParserContext Context { get; } - protected Dictionary Namespaces { get; } - protected IParserErrorHandler ErrorHandler { get; } - protected bool IgnoreNamespaceAttributes { get; set; } - - protected ElementParser (ParserContext parserContext, XElement element, Dictionary namespaces) - { - Context = parserContext ?? throw new ArgumentNullException (nameof (parserContext)); - ErrorHandler = parserContext.ErrorHandler; - Element = element ?? throw new ArgumentNullException (nameof (element)); - Namespaces = namespaces; - } - - public void Parse () - { - Dictionary> knownAttributes = GetKnownAttributes (); - Dictionary> knownElements = GetKnownChildElements (); - - if (Element.HasAttributes) { - if (knownAttributes == null) { - if (!IgnoreNamespaceAttributes || !AllAttributesAreNamespaceDeclarations (Element)) - ErrorHandler.Warning (Context.CurrentManifestURL, Element, $"Element '{Element.Name.GetFullName ()}' with parser {GetType().Name} has attributes but this version of the library does not support any of them"); - } else { - Action handler; - foreach (XAttribute attr in Element.Attributes ()) { - if (IgnoreNamespaceAttributes && attr.IsNamespaceDeclaration) - continue; - - if (!knownAttributes.TryGetValue (attr.Name.GetFullName (), out handler)) - handler = null; - - if (handler == null) { - ErrorHandler.Warning (Context.CurrentManifestURL, Element, $"Element '{Element.Name.GetFullName ()}' with parser {GetType().Name} has attribute '{attr.Name.GetFullName ()}' but this version of the library does not support it"); - continue; - } - - handler (attr); - } - } - } - - if (Element.HasElements) { - if (knownElements == null) { - ErrorHandler.Warning (Context.CurrentManifestURL, Element, $"Element '{Element.Name.GetFullName ()}' with parser {GetType().Name} has child elements but this version of the library does not support any children in this element"); - } else { - Action handler; - foreach (XElement child in Element.Elements ()) { - if (!knownElements.TryGetValue (child.Name.GetFullName (), out handler)) - handler = null; - - if (handler == null) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"Element '{Element.Name.GetFullName ()}' with parser {GetType().Name} has a child element '{child.Name.GetFullName ()}' but this version of the library does not support it"); - continue; - } - - handler (child); - } - } - } - - Parsed (); - } - - protected virtual void Parsed () - { - } - - bool AllAttributesAreNamespaceDeclarations (XElement element) - { - foreach (XAttribute attr in element.Attributes ()) { - if (!attr.IsNamespaceDeclaration) - return false; - } - - return true; - } - - protected string GetAttributeName (string namespaceName, string attributeName, bool warnIfMissing = true) - { - XNamespace xsins = GetNamespace (namespaceName); - if (xsins == null && warnIfMissing) - ErrorHandler.Warning (Context.CurrentManifestURL, Element, $"Required '{namespaceName}' namespace not declared, parsing results might be invalid"); - - return xsins == null ? $"{namespaceName}:{attributeName}" : (xsins + attributeName).GetFullName (); - } - - protected XNamespace GetNamespace (string name) - { - return GetNamespace (name, Namespaces); - } - - public static XNamespace GetNamespace (string name, Dictionary namespaces) - { - if (String.IsNullOrEmpty (name) || namespaces == null) - return null; - - XNamespace ns; - if (!namespaces.TryGetValue (name, out ns)) - return null; - - return ns; - } - - protected Uri EnsureAbsoluteUrl (Uri url) - { - if (url.IsAbsoluteUri) - return url; - - return new Uri (Context.BaseURL, url); - } - - protected abstract Dictionary> GetKnownChildElements (); - protected abstract Dictionary> GetKnownAttributes (); - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LibrariesParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LibrariesParser.cs deleted file mode 100644 index 5f6d6761ac6..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LibrariesParser.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class LibrariesParser : ElementParser - { - List libraries; - - public IList Libraries { get; private set; } - - public LibrariesParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"library", ParseChildElement_Archive} - }; - } - - void ParseChildElement_Archive (XElement element) - { - var lp = new LibraryParser (Context, element, Namespaces); - lp.Parse (); - if (lp.Library == null) - return; - - if (libraries == null) - libraries = new List (); - libraries.Add (lp.Library); - } - - protected override void Parsed () - { - base.Parsed (); - Libraries = libraries?.AsReadOnly (); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LibraryParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LibraryParser.cs deleted file mode 100644 index f3c23bfa675..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LibraryParser.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class LibraryParser : ElementParser - { - string localJarPath; - string name; - string description; - - public PackageLibrary Library { get; private set; } - - public LibraryParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return new Dictionary> (StringComparer.Ordinal) { - {"localJarPath", (XAttribute attribute) => localJarPath = attribute.Value ?? String.Empty }, - {"name", (XAttribute attribute) => name = attribute.Value ?? String.Empty } - }; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"description", (XElement element) => description = element.Value ?? String.Empty }, - }; - } - - protected override void Parsed () - { - base.Parsed (); - Library = new PackageLibrary { - LocalJarPath = localJarPath, - Name = name, - Description = description - }; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LicenseParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LicenseParser.cs deleted file mode 100644 index f6243e7ad70..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/LicenseParser.cs +++ /dev/null @@ -1,61 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class LicenseParser : ElementParser - { - string id; - string type; - - public License License { get; private set; } - - public LicenseParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return new Dictionary> (StringComparer.Ordinal) { - {"id", ParseAttribute_Id}, - {"type", ParseAttribute_Type} - }; - } - - protected override Dictionary> GetKnownChildElements () - { - return null; - } - - protected override void Parsed () - { - base.Parsed (); - if (String.IsNullOrEmpty (id)) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"License element is missing the required 'id' attribute"); - return; - } - License = new License (id, type, Element.Value ?? String.Empty); - } - - void ParseAttribute_Id (XAttribute attr) - { - id = attr?.Value ?? String.Empty; - } - - void ParseAttribute_Type (XAttribute attr) - { - type = attr?.Value ?? String.Empty; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/PackageTagParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/PackageTagParser.cs deleted file mode 100644 index 7fcaf2cadcf..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/PackageTagParser.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class PackageTagParser : ElementParser - { - string id; - string display; - - public PackageTag Tag { get; private set; } - - public PackageTagParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"id", (XElement e) => id = e.Value?.Trim ()}, - {"display", (XElement e) => display = e.Value?.Trim ()} - }; - } - - protected override void Parsed () - { - base.Parsed (); - - if (String.IsNullOrEmpty (id)) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"Missing child element 'id' on element {Element.Name}"); - return; - } - - Tag = new PackageTag (id, display); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/PackageVendorParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/PackageVendorParser.cs deleted file mode 100644 index b8217b80295..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/PackageVendorParser.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class PackageVendorParser : ElementParser - { - string id; - string display; - - public PackageVendor Vendor { get; private set; } - - public PackageVendorParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - {} - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"id", (XElement e) => id = e.Value?.Trim ()}, - {"display", (XElement e) => display = e.Value?.Trim ()} - }; - } - - protected override void Parsed () - { - base.Parsed (); - - if (String.IsNullOrEmpty (id)) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"Missing child element 'id' on element {Element.Name}"); - return; - } - - Vendor = new PackageVendor (id, display); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ParserContext.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ParserContext.cs deleted file mode 100644 index 605fe0224f2..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/ParserContext.cs +++ /dev/null @@ -1,82 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.IO; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - public class ParserContext : IDisposable - { - Uri currentManifestURL; - Uri currentManifestBaseURL; - - public IParserErrorHandler ErrorHandler { get; } - public Uri BaseURL { get; } - public Uri RepositoryManifestURL { get; } - public Uri AddonsListManifestURL { get; } - public Stream RepositoryManifest { get; } - public Stream AddonsListManifest { get; } - - public Uri CurrentManifestBaseURL => GetCurrentManifestBaseURL (); - - public Uri CurrentManifestURL { - get { return currentManifestURL; } - set { - currentManifestURL = value; - currentManifestBaseURL = null; - } - } - - - public IDictionary Licenses { get; private set; } - public IDictionary Channels { get; private set; } - - /// - /// Parse Context - /// - /// - /// - /// - /// - /// - /// If null, addons are not available - public ParserContext (IParserErrorHandler errorHandler, Uri baseURL, Uri repositoryManifestURL, Stream repositoryManifest, Uri addonsListManifestURL, Stream addonsListManifest = null) - { - ErrorHandler = errorHandler ?? throw new ArgumentNullException (nameof (errorHandler)); - BaseURL = baseURL ?? throw new ArgumentNullException (nameof (baseURL)); - RepositoryManifestURL = repositoryManifestURL ?? throw new ArgumentNullException (nameof (repositoryManifestURL)); - RepositoryManifest = repositoryManifest ?? throw new ArgumentNullException (nameof (repositoryManifest)); - AddonsListManifestURL = addonsListManifestURL ?? throw new ArgumentNullException (nameof (addonsListManifestURL)); - AddonsListManifest = addonsListManifest; - } - - public ParserContext (IParserErrorHandler errorHandler, Uri repositoryManifestURL) - { - ErrorHandler = errorHandler ?? throw new ArgumentNullException (nameof (errorHandler)); - RepositoryManifestURL = repositoryManifestURL ?? throw new ArgumentNullException (nameof (repositoryManifestURL)); - } - - public void Dispose () - { - RepositoryManifest?.Dispose (); - AddonsListManifest?.Dispose (); - } - - Uri GetCurrentManifestBaseURL () - { - if (currentManifestBaseURL != null) - return currentManifestBaseURL; - currentManifestBaseURL = currentManifestURL == null ? null : Helpers.GetBaseURL (currentManifestURL); - return currentManifestBaseURL; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RemotePackageParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RemotePackageParser.cs deleted file mode 100644 index ce360690dd1..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RemotePackageParser.cs +++ /dev/null @@ -1,158 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -using IOPath = System.IO.Path; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class RemotePackageParser : ElementParser - { - Repository repository; - - protected string Path { get; private set; } = String.Empty; - protected string FileSystemPath { get; private set; } - protected bool Obsolete { get; set; } - protected AndroidComponentInfo Info { get; private set; } - protected AndroidRevision Revision { get; private set; } - protected string DisplayName { get; private set; } = String.Empty; - protected IList Dependencies { get; private set; } - protected string ChannelID { get; private set; } - protected IList Archives { get; private set; } - protected string LicenseID { get; private set; } - - public RemotePackage Package { get; private set; } - - internal bool IncludeAllArchives { get; set; } // For Xamarin manifest generator this is 'true' - - public RemotePackageParser (Repository repository, ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - this.repository = repository ?? throw new ArgumentNullException (nameof (repository)); - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"type-details", ParseChildElement_TypeDetails}, - {"revision", ParseChildElement_Revision}, - {"display-name", ParseChildElement_DisplayName}, - {"uses-license", ParseChildElement_UsesLicense}, - {"channelRef", ParseChildElement_ChannelRef}, - {"dependencies", ParseChildElement_Dependencies}, - {"archives", ParseChildElement_Archives}, - }; - } - - protected override void Parsed () - { - base.Parsed (); - - Package = new RemotePackage (repository, Context.CurrentManifestURL, Element.GetLineInfo (), ErrorHandler, Archives) { - ChannelID = ChannelID, - Dependencies = Dependencies, - DisplayName = DisplayName, - FileSystemPath = FileSystemPath, - LicenseID = LicenseID, - Obsolete = Obsolete, - Path = Path, - Revision = Revision, - Info = Info, - IncludeAllArchives = IncludeAllArchives - }; - Package.Verify (); - } - - void ParseChildElement_Archives (XElement element) - { - var ap = new ArchivesParser (Context, element, Namespaces); - ap.Parse (); - Archives = ap.Archives; - } - - void ParseChildElement_Dependencies (XElement element) - { - var dp = new DependenciesParser (Context, element, Namespaces); - dp.Parse (); - Dependencies = dp.Dependencies; - } - - void ParseChildElement_ChannelRef (XElement element) - { - ChannelID = GetRefAttributeValue (element); - } - - void ParseChildElement_UsesLicense (XElement element) - { - LicenseID = GetRefAttributeValue (element); - } - - string GetRefAttributeValue (XElement element) - { - return element.Attribute ("ref")?.Value ?? String.Empty; - } - - void ParseChildElement_DisplayName (XElement element) - { - DisplayName = element?.Value ?? String.Empty; - } - - void ParseChildElement_Revision (XElement element) - { - var rp = new RevisionParser (Context, element, Namespaces); - rp.Parse (); - if (rp.Revision == null) { - ErrorHandler.Warning (Context.CurrentManifestURL, Element, "Package is missing a valid 'revision' child element"); - Revision = null; - } else - Revision = rp.Revision; - } - - void ParseChildElement_TypeDetails (XElement element) - { - if (Info != null) - ErrorHandler.Info (Context.CurrentManifestURL, element, "'type-details' element present more than once within this package. Will override old values."); - - Info = null; - TypeDetailsParser td = TypeDetailsParserFactory.CreateInstance (Context, element, Namespaces); - if (td == null) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, "Package is missing the 'type-details' child element"); - return; - } - td.Parse (); - - Info = td.Info; - } - - protected override Dictionary> GetKnownAttributes () - { - return new Dictionary> (StringComparer.Ordinal) { - {"path", ParseAttribute_Path}, - {"obsolete", ParseAttribute_Obsolete}, - }; - } - - void ParseAttribute_Obsolete (XAttribute attr) - { - string value = attr.Value; - if (String.IsNullOrEmpty (value)) - return; - Obsolete = string.Equals ("true", value, StringComparison.OrdinalIgnoreCase); - } - - void ParseAttribute_Path (XAttribute attr) - { - Path = attr.Value ?? String.Empty; - FileSystemPath = Path.Replace (';', IOPath.DirectorySeparatorChar); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RepositoryParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RepositoryParser.cs deleted file mode 100644 index 785765c500b..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RepositoryParser.cs +++ /dev/null @@ -1,127 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - public class RepositoryParser : ElementParser - { - Dictionary licenses; - Dictionary channels; - List packages; - GoogleV2Repository repository; - - public Dictionary Licenses => licenses; - public Dictionary Channels => channels; - public List Packages => packages; - public Uri RepositoryURL { get; } - - public bool IncludeAllArchives { get; set; } // For Xamarin manifest generator this is 'true' - - public RepositoryParser (GoogleV2Repository repository, ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - this.repository = repository ?? throw new ArgumentNullException (nameof (repository)); - IgnoreNamespaceAttributes = true; - RepositoryURL = parserContext.CurrentManifestURL; - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"license", ParseChildElement_License}, - {"channel", ParseChildElement_Channel}, - {"remotePackage", ParseChildElement_RemotePackage}, - }; - } - - void ParseChildElement_RemotePackage (XElement element) - { - var rp = new RemotePackageParser (repository, Context, element, Namespaces) { - IncludeAllArchives = IncludeAllArchives - }; - rp.Parse (); - AddPackage (rp.Package); - } - - void ParseChildElement_Channel (XElement element) - { - string id = element.Attribute ("id")?.Value; - if (String.IsNullOrEmpty (id)) { - ErrorHandler.Error (Context.CurrentManifestURL, element, $"Channel element misses the required 'id' attribute"); - return; - } - - string value = element.Value ?? id; - AddChannel (id, value); - } - - void ParseChildElement_License (XElement element) - { - var lp = new LicenseParser (Context, element, Namespaces); - lp.Parse (); - AddLicense (lp.License); - } - - void AddPackage (RemotePackage package) - { - if (packages == null) - packages = new List (); - packages.Add (package); - } - - void AddChannel (string id, string text) - { - AddDictionaryItem ( - new Channel (id, text), - id, - ref channels, - $"Duplicate channel with id '{id}' found. Will replace the old value" - ); - } - - void AddLicense (License license) - { - if (license == null) - return; - - AddDictionaryItem ( - license, - license.ID, - ref licenses, - $"Duplicate license with id '{license.ID}' found. Will replace the old value" - ); - } - - void AddDictionaryItem (T item, string key, ref Dictionary dict, string duplicateMessage, Func getDuplicateLocation = null) - { - if (dict == null) - dict = new Dictionary (StringComparer.Ordinal); - - if (dict.ContainsKey (key)) { - ErrorHandler.Warning (Context.CurrentManifestURL, Element, duplicateMessage); - if (getDuplicateLocation != null) { - string location = getDuplicateLocation (dict[key]); - if (!String.IsNullOrEmpty (location)) - ErrorHandler.Warning ($"Location of the previous value: {location}"); - } - dict[key] = item; - } else - dict.Add (key, item); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RevisionParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RevisionParser.cs deleted file mode 100644 index baf0e3d5fd7..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/RevisionParser.cs +++ /dev/null @@ -1,69 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class RevisionParser : ElementParser - { - int major; - int minor; - int micro; - int preview; - - public AndroidRevision Revision { get; private set; } - - public RevisionParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - major = minor = micro = preview = -1; - } - - protected override void Parsed () - { - base.Parsed (); - if (major < 0) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"Required 'major' version component is either missing or has invalid value ({major})"); - Revision = null; - } else - Revision = new AndroidRevision (major, minor, micro, preview); - } - - protected override Dictionary> GetKnownChildElements () - { - return new Dictionary> (StringComparer.Ordinal) { - {"major", (XElement e) => major = ParseValue (e)}, - {"minor", (XElement e) => minor = ParseValue (e)}, - {"micro", (XElement e) => micro = ParseValue (e)}, - {"preview", (XElement e) => preview = ParseValue (e)}, - }; - } - - int ParseValue (XElement element) - { - string v = element?.Value?.Trim (); - if (String.IsNullOrEmpty (v)) - return -1; - - int ret; - if (!Int32.TryParse (v, out ret)) { - ErrorHandler.Error (Context.CurrentManifestURL, element, $"Invalid value of element '{element.Name}'. Expected integer larger than 0"); - return -1; - } - - return ret; - } - - protected override Dictionary> GetKnownAttributes () - { - return null; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsAddOnParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsAddOnParser.cs deleted file mode 100644 index 95d0ac0a7c6..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsAddOnParser.cs +++ /dev/null @@ -1,61 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class TypeDetailsAddOnParser : TypeDetailsParser - { - public string ApiLevel { get; private set; } - public string CodeName { get; private set; } - public PackageVendor Vendor { get; private set; } - public PackageTag Tag { get; private set; } - public IList Libraries { get; private set; } - - public TypeDetailsAddOnParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - {} - - protected override Dictionary> GetKnownChildElements () - { - Dictionary> dict = EnsureDictionary (base.GetKnownChildElements ()); - dict["api-level"] = (XElement e) => ApiLevel = e.GetElementValue (); - dict["codename"] = (XElement e) => CodeName = e.GetElementValue (); - dict["libraries"] = ParseChildElement_Libraries; - dict["tag"] = (XElement e) => Tag = ParseChildElement_Tag (e); - dict["vendor"] = (XElement e) => Vendor = ParseChildElement_Vendor (e); - - // https://dl.google.com/android/repository/addon2-3.xml [605:4] - dict["base-extension"] = (XElement e) => {}; // ignore - return dict; - } - - void ParseChildElement_Libraries (XElement element) - { - var lp = new LibrariesParser (Context, element, Namespaces); - lp.Parse (); - if (lp.Libraries == null || lp.Libraries.Count == 0) - return; - Libraries = lp.Libraries; - } - - protected override AndroidComponentInfo CreateComponentInfo () - { - return new AndroidComponentInfoAddon (Type, ApiLevel, CodeName, Tag, Vendor, Libraries); - } - - protected override bool Validate () - { - return base.Validate () && ValidateApiLevel (ApiLevel); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsExtraParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsExtraParser.cs deleted file mode 100644 index aaf9ccd4ecb..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsExtraParser.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class TypeDetailsExtraParser : TypeDetailsParser - { - public PackageVendor Vendor { get; set; } - - public TypeDetailsExtraParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - {} - - protected override Dictionary> GetKnownChildElements () - { - Dictionary> dict = EnsureDictionary (base.GetKnownChildElements ()); - dict["vendor"] = (XElement e) => Vendor = ParseChildElement_Vendor (e); - return dict; - } - - protected override AndroidComponentInfo CreateComponentInfo () - { - return new AndroidComponentInfoExtra (Type, Vendor); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsGenericParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsGenericParser.cs deleted file mode 100644 index fd0e9b4eba5..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsGenericParser.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class TypeDetailsGenericParser : TypeDetailsParser - { - public TypeDetailsGenericParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { } - - protected override AndroidComponentInfo CreateComponentInfo () - { - return new AndroidComponentInfoGeneric (Type); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsMavenParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsMavenParser.cs deleted file mode 100644 index 95be22fe32a..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsMavenParser.cs +++ /dev/null @@ -1,36 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class TypeDetailsMavenParser : TypeDetailsParser - { - public PackageVendor Vendor { get; set; } - - public TypeDetailsMavenParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { } - - protected override Dictionary> GetKnownChildElements () - { - Dictionary> dict = EnsureDictionary (base.GetKnownChildElements ()); - dict["vendor"] = (XElement e) => Vendor = ParseChildElement_Vendor (e); - return dict; - } - - protected override AndroidComponentInfo CreateComponentInfo () - { - return new AndroidComponentInfoMaven (Type, Vendor); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsParser.cs deleted file mode 100644 index 463f9a52da9..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsParser.cs +++ /dev/null @@ -1,86 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - abstract class TypeDetailsParser : ElementParser - { - protected string Type { get; private set; } - public AndroidComponentInfo Info { get; private set; } - - protected TypeDetailsParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - { - IgnoreNamespaceAttributes = true; // for package.xml - } - - protected override Dictionary> GetKnownChildElements () - { - return null; - } - - protected override Dictionary> GetKnownAttributes () - { - return new Dictionary> (StringComparer.Ordinal) { - {GetAttributeName ("xsi", "type"), (XAttribute e) => Type = e.Value} - }; - } - - protected Dictionary> EnsureDictionary (Dictionary> dict) - { - if (dict == null) - return new Dictionary> (StringComparer.Ordinal); - return dict; - } - - protected override void Parsed () - { - base.Parsed (); - Info = Validate () ? CreateComponentInfo () : null; - } - - protected virtual bool Validate () - { - if (String.IsNullOrEmpty (Type)) // Not critical when missing, just warn - ErrorHandler.Warning (Context.CurrentManifestURL, Element, $"Type not specified on element {Element.Name}"); - - return true; - } - - protected bool ValidateApiLevel (string apiLevel) - { - if (String.IsNullOrEmpty (apiLevel)) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"Missing 'api-level' child element in element {Element.Name}"); - return false; - } - - return true; - } - - protected PackageTag ParseChildElement_Tag (XElement element) - { - var ptp = new PackageTagParser (Context, element, Namespaces); - ptp.Parse (); - return ptp.Tag; - } - - protected PackageVendor ParseChildElement_Vendor (XElement element) - { - var vp = new PackageVendorParser (Context, element, Namespaces); - vp.Parse (); - return vp.Vendor; - } - - protected abstract AndroidComponentInfo CreateComponentInfo (); - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsParserFactory.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsParserFactory.cs deleted file mode 100644 index 2f182e90cf2..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsParserFactory.cs +++ /dev/null @@ -1,133 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class TypeDetailsParserFactory - { - delegate TypeDetailsParser TypeCreator (ParserContext parserContext, XElement element, Dictionary namespaces); - - static TypeCreator genericCreator = (ParserContext parserContext, XElement element, Dictionary namespaces) => new TypeDetailsGenericParser (parserContext, element, namespaces); - static TypeCreator platfomCreator = (ParserContext parserContext, XElement element, Dictionary namespaces) => new TypeDetailsPlatformParser (parserContext, element, namespaces); - static TypeCreator sourceCreator = (ParserContext parserContext, XElement element, Dictionary namespaces) => new TypeDetailsSourceParser (parserContext, element, namespaces); - static TypeCreator systemImageCreator = (ParserContext parserContext, XElement element, Dictionary namespaces) => new TypeDetailsSystemImageParser (parserContext, element, namespaces); - static TypeCreator addonCreator = (ParserContext parserContext, XElement element, Dictionary namespaces) => new TypeDetailsAddOnParser (parserContext, element, namespaces); - static TypeCreator extraCreator = (ParserContext parserContext, XElement element, Dictionary namespaces) => new TypeDetailsExtraParser (parserContext, element, namespaces); - static TypeCreator mavenCreator = (ParserContext parserContext, XElement element, Dictionary namespaces) => new TypeDetailsMavenParser (parserContext, element, namespaces); - - // The map looks a bit convoluted but it is necessary in order to support type details lookups from different sources. - // The package type is namespaced and uses different namespace names (but the same URIs) in the online repository and - // package.xml on disk. The namespace-less version is just a fallback. - static readonly Dictionary typeDetailsMap = new Dictionary { - // Generic - {"genericDetailsType", genericCreator}, - {"generic:genericDetailsType", genericCreator}, - {"http://schemas.android.com/repository/android/generic/01:genericDetailsType", genericCreator}, - - // Platform - {"platformDetailsType", platfomCreator}, - {"sdk:platformDetailsType", platfomCreator}, - {"http://schemas.android.com/sdk/android/repo/repository2/01:platformDetailsType", platfomCreator}, - - // Source - {"sourceDetailsType", sourceCreator}, - {"sdk:sourceDetailsType", sourceCreator}, - {"http://schemas.android.com/sdk/android/repo/repository2/01:sourceDetailsType", sourceCreator}, - - // System image - {"sysImgDetailsType", systemImageCreator}, - {"sys-img:sysImgDetailsType", systemImageCreator}, - {"http://schemas.android.com/sdk/android/repo/sys-img2/01:sysImgDetailsType", systemImageCreator}, - - // Addon - {"addonDetailsType", addonCreator}, - {"addon:addonDetailsType", addonCreator}, - {"http://schemas.android.com/sdk/android/repo/addon2/01:addonDetailsType", addonCreator}, - - // Extra - {"extraDetailsType", extraCreator}, - {"addon:extraDetailsType", extraCreator}, - {"http://schemas.android.com/sdk/android/repo/addon2/01:extraDetailsType", extraCreator}, - - // Maven - {"mavenType", mavenCreator}, - {"addon:mavenType", mavenCreator}, - {"http://schemas.android.com/sdk/android/repo/addon2/01:mavenType", mavenCreator}, - }; - - public static TypeDetailsParser CreateInstance (ParserContext parserContext, XElement element, Dictionary namespaces) - { - if (parserContext == null) - throw new ArgumentNullException (nameof (parserContext)); - - if (element == null) - throw new ArgumentNullException (nameof (element)); - - element.GetNamespaces (parserContext.CurrentManifestURL, ref namespaces); - XNamespace xsins = ElementParser.GetNamespace ("xsi", namespaces); - if (xsins == null) { - parserContext.ErrorHandler.Error (parserContext.CurrentManifestURL, element, $"Namespace 'xsi' undefined, unable to determine the TypeDetails mapping"); - return null; - } - - XAttribute xsiType = element.GetAttribute (xsins, "type"); - if (xsiType == null) { - parserContext.ErrorHandler.Error (parserContext.CurrentManifestURL, element, $"'xsi:type' attribute not found on element {element.Name} {element.GetLocation ()}"); - return null; - } - - TypeCreator creator = FindCreator (parserContext, xsiType.Value, element, namespaces); - if (creator == null) - return null; - - TypeDetailsParser ret = creator (parserContext, element, namespaces); - if (ret == null) { - parserContext.ErrorHandler.Error (parserContext.CurrentManifestURL, element, $"Failed to map TypeDetails element {element.Name} ('{xsiType.Value}') to a managed type {element.GetLocation ()}"); - return null; - } - - return ret; - } - - static TypeCreator FindCreator (ParserContext parserContext, string typeName, XElement element, Dictionary namespaces) - { - TypeCreator creator = LookupCreator (typeName); - if (creator != null) - return creator; - - string[] parts = typeName.Split (':'); - if (parts.Length != 2) - goto noCreator; - - XNamespace ns = ElementParser.GetNamespace (parts[0], namespaces); - creator = LookupCreator ($"{ns.NamespaceName}:{parts[1]}"); - if (creator != null) - return creator; - - creator = LookupCreator (parts[1]); - if (creator == null) - goto noCreator; - return creator; - - noCreator: - parserContext.ErrorHandler.Error (parserContext.CurrentManifestURL, element, $"Unknown type of the TypeDetails element {element.Name}: '{typeName}' {element.GetLocation ()}"); - return null; - } - - static TypeCreator LookupCreator (string typeName) - { - if (!typeDetailsMap.TryGetValue (typeName, out TypeCreator creator) || creator == null) - return null; - return creator; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsPlatformParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsPlatformParser.cs deleted file mode 100644 index e649128cf6b..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsPlatformParser.cs +++ /dev/null @@ -1,71 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class TypeDetailsPlatformParser : TypeDetailsParser - { - protected string ApiLevel { get; private set; } - protected string CodeName { get; private set; } - protected string LayoutLibApi { get; private set; } - protected string BaseExtension { get; private set; } - protected string ExtensionLevel { get; private set; } - - public TypeDetailsPlatformParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - {} - - protected override Dictionary> GetKnownChildElements () - { - Dictionary> dict = EnsureDictionary (base.GetKnownChildElements ()); - dict["api-level"] = (XElement e) => ApiLevel = e.GetElementValue (); - dict["codename"] = (XElement e) => CodeName = e.GetElementValue (); - dict["layoutlib"] = ParseChildElement_LayoutLib; - - // https://dl.google.com/android/repository/repository2-3.xml [304:4] - dict["base-extension"] = (XElement e) => BaseExtension = e.GetElementValue (); - - // https://dl.google.com/android/repository/repository2-3.xml [304:4] - dict["extension-level"] = (XElement e) => ExtensionLevel = e.GetElementValue (); - - return dict; - } - - protected override AndroidComponentInfo CreateComponentInfo () - { - // Android SDK component is considered "experimental" / "not stable" when codename is not empty & "base-extension" is not empty - // See android-Tiramisu for example - return new AndroidComponentInfoPlatform (Type, ApiLevel, CodeName, LayoutLibApi) { - Preview = !string.IsNullOrEmpty (CodeName) && !string.IsNullOrEmpty (BaseExtension) && !string.IsNullOrEmpty (ExtensionLevel), - }; - } - - protected override bool Validate () - { - bool ret = base.Validate () && ValidateApiLevel (ApiLevel); - - if (String.IsNullOrEmpty (LayoutLibApi)) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"Missing attribute 'layoutlib' on element {Element.Name}"); - ret = false; - } - - return ret; - } - - void ParseChildElement_LayoutLib (XElement element) - { - XAttribute api = element.GetAttribute ("api"); - LayoutLibApi = api?.Value?.Trim (); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsSourceParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsSourceParser.cs deleted file mode 100644 index a1d0f2d2774..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsSourceParser.cs +++ /dev/null @@ -1,48 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class TypeDetailsSourceParser : TypeDetailsParser - { - protected string ApiLevel { get; private set; } - protected string CodeName { get; private set; } - - public TypeDetailsSourceParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - {} - - protected override Dictionary> GetKnownChildElements () - { - Dictionary> dict = EnsureDictionary (base.GetKnownChildElements ()); - dict["api-level"] = (XElement e) => ApiLevel = e.GetElementValue (); - dict["codename"] = (XElement e) => CodeName = e.GetElementValue (); - - // https://dl.google.com/android/repository/repository2-3.xml [1200:4] - dict["base-extension"] = (XElement e) => {}; // ignore - dict["extension-level"] = (XElement e) => { }; // ignore - - return dict; - } - - protected override AndroidComponentInfo CreateComponentInfo () - { - return new AndroidComponentInfoSource (Type, ApiLevel, CodeName); - } - - protected override bool Validate () - { - return base.Validate () && ValidateApiLevel (ApiLevel); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsSystemImageParser.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsSystemImageParser.cs deleted file mode 100644 index efad401481d..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/Parsing/TypeDetailsSystemImageParser.cs +++ /dev/null @@ -1,79 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2.Parsing -{ - class TypeDetailsSystemImageParser : TypeDetailsParser - { - protected AndroidSystemImageAbi? Abi { get; private set; } - protected string AbiName { get; private set; } - protected string ApiLevel { get; private set; } - protected string CodeName { get; private set; } - protected PackageTag Tag { get; private set; } - protected PackageVendor Vendor { get; private set; } - - public TypeDetailsSystemImageParser (ParserContext parserContext, XElement element, Dictionary namespaces = null) : base (parserContext, element, namespaces) - {} - - protected override Dictionary> GetKnownChildElements () - { - Dictionary> dict = EnsureDictionary (base.GetKnownChildElements ()); - dict["abi"] = ParseChildElement_ABI; - dict["api-level"] = (XElement e) => ApiLevel = e.GetElementValue (); - dict["codename"] = (XElement e) => CodeName = e.GetElementValue (); - dict["tag"] = (XElement e) => Tag = ParseChildElement_Tag (e); - dict["vendor"] = (XElement e) => Vendor = ParseChildElement_Vendor (e); - - // https://dl.google.com/android/repository/sys-img/android/sys-img2-3.xml [702:4] - dict["base-extension"] = (XElement e) => {}; // ignore - - return dict; - } - - protected override AndroidComponentInfo CreateComponentInfo () - { - return new AndroidComponentInfoSystemImage (Type, Abi.Value, AbiName, ApiLevel, CodeName, Tag, Vendor); - } - - void ParseChildElement_ABI (XElement element) - { - string abiName = element.Value?.Trim (); - - if (String.IsNullOrEmpty (abiName)) - return; - - AbiName = abiName; - AndroidSystemImageAbi abi = AndroidComponentInfoSystemImage.DefaultAbi; - try { - abi = AndroidUtilities.StringToAbi (abiName); - } catch (ArgumentOutOfRangeException) { - ErrorHandler.Warning (Context.CurrentManifestURL, Element, $"Unknown ABI: '{abiName}'"); - return; - } - Abi = abi; - } - - protected override bool Validate () - { - bool ret = base.Validate () && ValidateApiLevel (ApiLevel); - - if (!Abi.HasValue) { - ErrorHandler.Error (Context.CurrentManifestURL, Element, $"Missing 'abi' child element in element {Element.Name}"); - ret = false; - } - - return ret; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/RemotePackage.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/RemotePackage.cs deleted file mode 100644 index fc3023858f3..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/RemotePackage.cs +++ /dev/null @@ -1,256 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Xml; -using System.Xml.Linq; - -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.Common; - -using IOPath = System.IO.Path; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2 -{ - public class RemotePackage : BasePackage, IEquatable - { - IParserErrorHandler errorHandler; - - public override AndroidComponentType ComponentType => GetComponentType (Info); - public override Channel Channel => Repository.GetChannel (ChannelID); - public string ChannelID { get; set; } - - public bool IncludeAllArchives { get; set; } // For Xamarin manifest generator this is 'true' - - public RemotePackage (Repository repository, Uri manifestURL, IXmlLineInfo location, IParserErrorHandler errorHandler, IList archives) : base (repository, manifestURL, location, archives) - { - this.errorHandler = errorHandler ?? throw new ArgumentNullException (nameof (errorHandler)); - } - - // This is just a way to see in the logs whether the package is sane, apply some hacks to work around bugs in - // Google manifests etc. - public void Verify () - { - OnStatusChange (AndroidComponentStatus.VerificationStarted); - try { - DoVerify (); - } finally { - OnStatusChange (AndroidComponentStatus.VerificationEnded); - } - } - - void DoVerify () - { - string location = Location?.AsString () ?? String.Empty; - string path = String.IsNullOrEmpty (Path) ? "Unknown" : Path; - - if (OriginalArchives?.Any () == true) { - PopulatePlatformArchives (Info is AndroidComponentInfoSystemImage || IncludeAllArchives); - if (Info is AndroidComponentInfoSystemImage && !Archives.Any ()) { - // This is a workaround for a bug in the Google manifest which has the following archives entry: - // - // - // - // - // - // 238333358 - // 7cf2ad756e54a3acfd81064b63cb0cb9dff2798d - // armeabi-v7a-23_r06.zip - // - // windows - // - // - // - // which marks the archive as valid only on Windows. The issue is that system images are not - // specific to any host OS since they contain Android installation to be executed inside the - // emulator. That's why we ignore the host OS check for system images here. - Archives = new List { OriginalArchives.First () }.AsReadOnly (); - } - } - - if (Archives == null || Archives.Count == 0) - Logger.Warning ($"Package loaded from {ManifestURL} {location}, with path '{path}' has no valid archives (Host OS: {AndroidSDKContext.Instance.Platform})"); - } - - public static RemotePackage Clone (RemotePackage source) - { - if (source == null) - return null; - - // Archive instance aren't cloned because we want them to be shared amongst all the SDK instances and as the list is read-only, there's no - // need to clone it either. - var cloned = new RemotePackage (source.Repository, source.ManifestURL, source.Location, source.errorHandler, source.OriginalArchives) { - IsEssential = source.IsEssential, - IgnoreFailure = source.IgnoreFailure, - Present = source.Present, - NeedsUpdate = source.NeedsUpdate, - Path = source.Path, - FileSystemPath = source.FileSystemPath, - Obsolete = source.Obsolete, - Info = source.Info, - Revision = source.Revision, - InstalledRevision = source.InstalledRevision, - DisplayName = source.DisplayName, - Dependencies = source.Dependencies, - ChannelID = source.ChannelID, - LicenseID = source.LicenseID, - ForceInstallation = source.ForceInstallation, - }; - cloned.Verify (); - - return cloned; - } - - protected override PackageMetadata CreateMetadata (BasePackage component) - { - return new RemotePackageMetadata (component as RemotePackage); - } - - protected override bool MetadataChanged (PackageMetadata metadata, bool update = false, bool ignoreInstalledState = false) - { - if (!base.MetadataChanged (metadata, update, ignoreInstalledState)) - return false; - - return MetadataChanged (metadata as RemotePackageMetadata, update, ignoreInstalledState); - } - - public override void RefreshMetadata (IAndroidComponent component, bool ignoreInstalledState = true) - { - RefreshMetadata (component as RemotePackage); - } - - void RefreshMetadata (RemotePackage rp, bool ignoreInstalledState = true) - { - if (rp == null) - throw new ArgumentNullException (nameof (rp)); - - MetadataChanged (CreateMetadata (rp), true, ignoreInstalledState); - } - - bool MetadataChanged (RemotePackageMetadata metadata, bool update, bool ignoreInstalledState) - { - if (metadata == null) - throw new ArgumentNullException (nameof (metadata)); - - bool haveChanges = false; - if (!string.Equals (metadata.ChannelID, ChannelID, StringComparison.Ordinal)) { - if (update) { - ChannelID = metadata.ChannelID; - haveChanges = true; - } else - return true; - } - - if (!string.Equals (metadata.LicenseID, LicenseID, StringComparison.Ordinal)) { - if (update) { - LicenseID = metadata.LicenseID; - haveChanges = true; - } else - return true; - } - - return haveChanges; - } - - AndroidComponentType GetComponentType (AndroidComponentInfo info) - { - if (info is AndroidComponentInfoAddon) - return AndroidComponentType.Addon; - - if (info is AndroidComponentInfoExtra) - return AndroidComponentType.Extra; - - if (info is AndroidComponentInfoGeneric) - return AndroidComponentType.Generic; - - if (info is AndroidComponentInfoMaven) - return AndroidComponentType.Maven; - - if (info is AndroidComponentInfoPlatform) - return AndroidComponentType.Platform; - - if (info is AndroidComponentInfoSource) - return AndroidComponentType.Source; - - if (info is AndroidComponentInfoSystemImage) - return AndroidComponentType.SystemImage; - - errorHandler.Debug ($"Unknown component info type '{info?.GetType ()}'"); - return AndroidComponentType.Unknown; - } - - public override bool MatchesTo (IAndroidComponent other) - { - if (!(other is RemotePackage)) - return false; - - return base.MatchesTo (other); - } - - - public override bool BasicMetadataEquals (BasePackage other) - { - if (!base.BasicMetadataEquals (other)) - return false; - - return BasicMetadataEquals (other as RemotePackage); - } - - bool BasicMetadataEquals (RemotePackage other) - { - if (!string.Equals (ChannelID, other.ChannelID, StringComparison.Ordinal)) - return false; - - return true; - } - - public bool Equals (RemotePackage other) - { - if (other == null) - return false; - - return base.Equals (other as BasePackage); - } - - public override bool Equals (object obj) - { - return Equals (obj as RemotePackage); - } - - public override int GetHashCode () - { - int hashCode = base.GetHashCode (); - - return hashCode.XorWith (ChannelID?.GetHashCode ()); - } - - protected override void LogError (string message) - { - errorHandler.Error (message); - } - - protected override void LogWarning (string message) - { - errorHandler.Warning (message); - } - - protected override void LogInfo (string message) - { - errorHandler.Info (message); - } - - protected override void LogDebug (string message) - { - errorHandler.Debug (message); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/RemotePackageMetadata.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/RemotePackageMetadata.cs deleted file mode 100644 index 39c9cf5a45a..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/GoogleV2/RemotePackageMetadata.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2018, Microsoft Corp. (https://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; - -using Xamarin.Installer.AndroidSDK.Common; - -namespace Xamarin.Installer.AndroidSDK.GoogleV2 -{ - class RemotePackageMetadata : PackageMetadata - { - public string ChannelID { get; set; } - - public RemotePackageMetadata (RemotePackage rp) : base (rp) - { - if (rp == null) - throw new ArgumentNullException (nameof (rp)); - ChannelID = rp.ChannelID; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Helpers.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Helpers.cs deleted file mode 100644 index 610c838714f..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Helpers.cs +++ /dev/null @@ -1,106 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Marek Habersack -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using System.Xml.Linq; - -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - public class Helpers - { - static readonly string utf8BOM = Encoding.UTF8.GetString (Encoding.UTF8.GetPreamble ()); - - public static void AddDictionaryItem (T item, string key, ref Dictionary dict, Action duplicateHandler = null) - { - if (dict == null) - dict = new Dictionary (StringComparer.Ordinal); - - if (dict.ContainsKey (key)) { - if (duplicateHandler != null) - duplicateHandler (key); - dict[key] = item; - } else - dict.Add (key, item); - } - - public static string GetComponentArchiveSelector (string os, string arch, uint osbits) - { - os = os?.Trim (); - if (String.IsNullOrEmpty (os)) - os = "any"; - arch = arch?.Trim (); - if (String.IsNullOrEmpty (arch)) - arch = "any"; - - return os + arch + osbits; - } - - public static XmlDocument LoadXML (string xml, string documentName, bool initializeNamespace, out XmlNamespaceManager nsmgr) - { - // XmlDocument breaks when the XML starts with the BOM. Funny thing is, the XML - // was previously written by XmlWriter... Because why not...??? - if (xml.StartsWith (utf8BOM, StringComparison.Ordinal)) - xml = xml.Remove (0, utf8BOM.Length); - var doc = new XmlDocument (); - doc.LoadXml (xml); - - nsmgr = new XmlNamespaceManager (doc.NameTable); - if (initializeNamespace) { - XmlElement root = doc.DocumentElement; - if (root.Attributes != null) { - - foreach (XmlAttribute attr in root.Attributes) { - if (attr == null || String.IsNullOrEmpty (attr.Name)) - continue; - - string name = GetXMLNamespaceName (attr.Name); - if (String.IsNullOrEmpty (name)) - continue; - - Logger.Debug ("Adding {0} XML namespace '{1}' == '{2}'", documentName, name, attr.Value); - nsmgr.AddNamespace (name, attr.Value); - } - } - } - - return doc; - } - - public static Uri GetBaseURL (Uri fullUrl) - { - if (fullUrl == null) - throw new ArgumentNullException (nameof (fullUrl)); - - string url = fullUrl.ToString (); - int fileStart = url.LastIndexOf ('/'); - if (fileStart >= 0) - return new Uri (url.Substring (0, fileStart + 1)); - else - return fullUrl; - } - - static string GetXMLNamespaceName (string xmlns) - { - xmlns = xmlns.SafeTrim (); - if (String.IsNullOrEmpty (xmlns)) - return String.Empty; - - int colon; - if ((colon = xmlns.IndexOf (':')) < 0) - return xmlns; - - return xmlns.Substring (colon + 1); - } - } - -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/IProgressMonitor.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/IProgressMonitor.cs deleted file mode 100644 index a6f7a9559f1..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/IProgressMonitor.cs +++ /dev/null @@ -1,102 +0,0 @@ -// -// IProgressMonitor.cs -// -// Author: -// Vsevolod Kukol -// -// Copyright (c) 2017, Microsoft, Inc -// - -using System; -using System.Threading; - -namespace Xamarin.Installer.AndroidSDK.Manager -{ - /// - /// The cancellable progress monitor can cancel a running operation. - /// - /// - /// Implement this interface to be able tonotify the SDK Manager that the running operation should - /// be canceled. - /// - public interface ICancellableProgressMonitor : IProgressMonitor, IDisposable - { - /// - /// Gets the cancellation token. - /// - /// The cancellation token. - CancellationToken CancellationToken { get; } - - /// - /// Gets a value indicating whether this - /// should be disposed after the work is done. - /// - /// true to dispose when finished; otherwise, false. - bool DisposeOnFinish { get; } - } - - /// - /// A progress monitor with total progress will be notified by the SDK Manager with overall progress of installation steps - /// - public interface IProgressMonitorWithTotalProgress : ICancellableProgressMonitor - { - /// - /// Reports the total progress of all the download and installation steps - /// - /// Overall progress percentage from 0.0 to 1.0 - /// Total number of main components to be installed - /// Index of the main component currently being installed - /// Total number of subcomponents to be installed for the current main component - /// Index of the subcomponent currently being installed - void ReportTotalProgress (double loadPercentage, - int mainComponentsCount, int mainComponentIndex, - int subComponentsCount, int subComponentIndex); - } - - /// - /// A progress monitor will be notified by the SDK Manager of all installation steps. - /// - /// - /// Implement this interface to observe all installation steps and progress updates. - /// - public interface IProgressMonitor - { - /// - /// Begin a new step. - /// - /// The translated message associated with the step to be presented to the user. - void BeginStep (string step); - - /// - /// Begin a new step with progress notification. - /// - /// The translated message associated with the step to be presented to the user. - /// The total length of the progress to be done in this step. - void BeginStep (string step, long totalWork); - - /// - /// End the last step started with BeginStep () - /// - void EndStep (AndroidSDKComponentInstallationResult result = null); - - /// - /// Reports the progress of the currently running step. - /// - /// The current step progress. - void ReportProgress (long work); - - /// - /// Show a message to the user. - /// - /// The message to be shown. - /// Messages provide additional status information for the currently running step. - void ReportMessage (string message); - - /// - /// Notify the user when an error occured. - /// - /// The error message. - /// The exception - void ReportError (string message, Exception ex); - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/JavaDependencyInstaller.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/JavaDependencyInstaller.cs deleted file mode 100644 index f97d7145a15..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/JavaDependencyInstaller.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using Xamarin.Installer.Common; -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.AndroidSDK.Manager; -using Xamarin.Installer.AndroidSDK.Xamarin; - -namespace Xamarin.Installer.AndroidSDK -{ - public class JavaDependencyInstaller - { - public Repository Repository { get; private set; } - - public string JdkPath { get; set; } - - public JavaDependencyInstaller (IHelpers helpers = null, Uri manifestURL = null, bool useManifestCaching = false) - { - CommonUtilities.Helpers = helpers ?? new Helper (); - Repository = new XamarinRepository (manifestURL, useManifestCaching); - } - - public void Discover () - { - if (!Repository.Parsed) { - Repository.Parse (); - } - } - - public IEnumerable GetJdkArchivesWithVersion (AndroidRevision version) - { - return Repository.JdkComponents.Where (j => j.Revision == version).SelectMany (j => j.Archives); - } - - public JdkArchive GetFirstValidJdkArchiveWithVersion (AndroidRevision version) - { - var jdks = GetJdkArchivesWithVersion (version); - return jdks.FirstOrDefault (j => j.IsValidForSystem ()); - } - - public bool GetJdkRevision (out AndroidRevision version) - { - if (string.IsNullOrEmpty (JdkPath)) { - version = new AndroidRevision (0); - return false; - } - var props = AndroidUtilities.ReadAndroidProperties (Path.Combine (JdkPath, "release")); - bool foundUnparsedVersion = props.GetProperty ("JAVA_VERSION", out string javaVersion); - javaVersion = javaVersion?.Replace ("\"", string.Empty).Replace ("'", string.Empty); - version = new AndroidRevision (javaVersion); - return foundUnparsedVersion && version != new AndroidRevision (0); - } - - public bool IsJdkPathValid () - { - if (string.IsNullOrEmpty (JdkPath)) { - return false; - } - - // If the requested path is in a known VS installation Program Files path on Windows, request a different path - if (Platform.IsWindows) { - if (JdkPath.StartsWith (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles), StringComparison.OrdinalIgnoreCase) - || JdkPath.StartsWith (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86), StringComparison.OrdinalIgnoreCase)) { - return false; - } - } - - // If the requested path is not writable, request a different path - try { - Directory.CreateDirectory (JdkPath); - using var _ = File.Create (Path.Combine (JdkPath, "tmp"), 1, FileOptions.DeleteOnClose); - } catch (Exception) { - return false; - } - - return true; - } - - public void InstallJdk (JdkArchive archive) - { - var unzipDestination = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ()); - Directory.CreateDirectory (unzipDestination); - - if (Platform.IsWindows) { - CommonUtilities.Helpers.Unzip (unzipDestination, archive.DownloadedFilePath, null, null); - } else { - var extractResult = CommonUtilities.RunCommand ( - workingDirectory: unzipDestination, - command: "/usr/bin/tar", - exitCode: out int exitCode, - arguments: new [] { "-xzf", archive.DownloadedFilePath }); - if (exitCode != 0) - throw new Exception ($"Failed to extract temp Java SDK archive {archive.DownloadedFilePath}:\n{extractResult}"); - } - - var jdkSubDir = Directory.GetDirectories (unzipDestination).FirstOrDefault (); - if (Platform.IsMac) { - jdkSubDir = Path.Combine (jdkSubDir, "Contents", "Home"); - } - RemoveJdk (); - CommonUtilities.MoveDirectory (jdkSubDir, JdkPath); - if (Directory.Exists (unzipDestination)) - Directory.Delete (unzipDestination, true); - } - - public void RemoveJdk () - { - if (Directory.Exists (JdkPath)) - Directory.Delete (JdkPath, true); - } - - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/LocalManifestProvider.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/LocalManifestProvider.cs deleted file mode 100644 index 73f48405e14..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/LocalManifestProvider.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.IO; - -using Xamarin.Installer.AndroidSDK; -using Xamarin.Installer.AndroidSDK.Manager; -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - public interface ILocalManifestProvider { - void SaveManifest (string manifest, string fileName = null); - string GetManifest (string fileName = null); - } - class LocalManifestProvider: ILocalManifestProvider - { - const string AppName = "AndroidSDKManager"; - - const string XAMARIN_MANIFEST_FILE_NAME = "XamarinManifest.xml"; - const string GOOGLE_MANIFEST_FILE_NAME = "GoogleManifest.xml"; - - static string CacheFolder = ConfigManager.ConfigFolder; - - public static LocalManifestProvider CreateGoogleManifestProvider () - { - return new LocalManifestProvider (AndroidManifestType.GoogleV2); - } - - public static LocalManifestProvider CreateXamarinManifestProvider () - { - return new LocalManifestProvider (AndroidManifestType.Xamarin); - } - - AndroidManifestType manifestType; - - - LocalManifestProvider (AndroidManifestType manifestType) - { - this.manifestType = manifestType; - if (manifestType != AndroidManifestType.GoogleV2 && manifestType != AndroidManifestType.Xamarin) - throw new ArgumentException ("LocalManifestProvider supports GoogleV2 and Xamarin manifest types only", "manifestType"); - } - - public void SaveManifest (string manifest, string fileName = null) - { - try { - if (!Directory.Exists (CacheFolder)) - Directory.CreateDirectory (CacheFolder); - - File.WriteAllText (GetManifestFilePath (fileName), manifest); - } catch (Exception ex) { - Logger.Error ($"Failed to save manifest: {ex}"); - } - } - - public string GetManifest (string fileName = null) - { - var manifestFilePath = GetManifestFilePath(fileName); - if (!File.Exists(manifestFilePath)) - { - Logger.Info("GetManifest:: manifestFilePath " + manifestFilePath); - return null; - } - - - try { - return File.ReadAllText (manifestFilePath); - } catch (Exception ex) { - Logger.Error ($"Failed to load local manifest: {ex}"); - } - - return null; - } - - string GetManifestFilePath (string fileName = null) - { - fileName = fileName ?? ManifestFileName; - return Path.Combine (CacheFolder, fileName); - } - - string ManifestFileName { - get { - return manifestType == AndroidManifestType.Xamarin ? XAMARIN_MANIFEST_FILE_NAME : GOOGLE_MANIFEST_FILE_NAME; - } - } - - } -} \ No newline at end of file diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/LocalSDK/LocalSDKRepository.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/LocalSDK/LocalSDKRepository.cs deleted file mode 100644 index bda03e236cf..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/LocalSDK/LocalSDKRepository.cs +++ /dev/null @@ -1,388 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft, Inc (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.IO; -using System.Xml.Linq; -using System.Linq; - -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.AndroidSDK.GoogleV2; -using Xamarin.Installer.AndroidSDK.GoogleV2.Parsing; -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK.LocalSDK -{ - class LocalSDKRepository : Repository - { - sealed class InformationSource - { - public string Name; - public Func Parser; - } - - IParserErrorHandler errorHandler; - - readonly List component_info_sources; - - public LocalSDKRepository (IParserErrorHandler errorHandler) : base ("Local SDK Repository") - { - this.errorHandler = errorHandler ?? throw new ArgumentNullException (nameof (errorHandler)); - component_info_sources = new List { - new InformationSource {Name = "package.xml", Parser = Parse_Package_Xml}, - new InformationSource {Name = "source.properties", Parser = Parse_Source_Properties} - }; - } - - public override void Parse () - { - // nothing to do here - Parsed = true; - } - - protected override void DetectInternal (AndroidSdkInstance sdkInstance) - { - if (!Directory.Exists (sdkInstance.Path)) { - Logger.Info ($"SDK directory '{sdkInstance.Path}' doesn't exist, unable to perform detection"); - return; - } - - Logger.Debug ($"Detecting Android SDK in '{sdkInstance.Path}'"); - foreach (string dir in Directory.EnumerateDirectories (sdkInstance.Path, "*", SearchOption.AllDirectories)) { - MaybeParseComponent (dir, sdkInstance.Path); - } - sdkInstance.Components = Components.Where(c => c != null).Select(c => c.Clone()).ToList(); - base.DetectInternal(sdkInstance); - } - - void MaybeParseComponent (string dir, string sdkRoot) - { - foreach (InformationSource info in component_info_sources) { - if (String.IsNullOrEmpty (info?.Name) || info?.Parser == null) - continue; - - string file = Path.Combine (dir, info.Name); - if (!File.Exists (file)) - continue; - - Logger.Debug ($"Parsing Android component information from '{file}'"); - if (info.Parser (file, sdkRoot)) - return; - } - } - - bool Parse_Package_Xml (string filePath, string sdkRoot) - { - var manifest = new Uri (filePath); - var namespaces = new Dictionary (StringComparer.Ordinal); - using (var parserContext = new ParserContext (errorHandler, manifest)) { - parserContext.CurrentManifestURL = manifest; - using (var fs = File.OpenRead (filePath)) { - var doc = ParseManifest ("LocalAndroidManifest", fs); - doc.Root.GetNamespaces (manifest, ref namespaces); - Namespaces = namespaces; - XElement element = doc.Root.Element ("localPackage"); - if (element == null) - return false; - - var rp = new RemotePackageParser (this, parserContext, element, Namespaces); - rp.Parse (); - AddComponent (rp.Package); - if (rp.Package == null) - return false; - element = doc.Root.Element ("license"); - if (element == null) - return true; - var lp = new LicenseParser (parserContext, element, Namespaces); - lp.Parse (); - AddLicense (lp.License); - } - } - return true; - } - - bool Parse_Source_Properties (string filePath, string sdkRoot) - { - var props = AndroidUtilities.ReadAndroidProperties (filePath); - - string sv; - AndroidRevision installedRevision; - props.GetProperty ("Pkg.Revision", out sv); - if (!String.IsNullOrEmpty (sv)) - installedRevision = new AndroidRevision (sv, false); - else - installedRevision = new AndroidRevision (0); - - string displayName; - props.GetProperty ("Pkg.Desc", out displayName); - - string path; - props.GetProperty ("Pkg.Path", out path); - - string license; - props.GetProperty ("Pkg.License", out license); - - string licenseId; - props.GetProperty ("Pkg.LicenseRef", out licenseId); - - string manifestUrl; - props.GetProperty ("Pkg.SourceUrl", out manifestUrl); - - // Detect component info - AndroidComponentInfo info = null; - - // Platform - if (props.GetProperty ("Platform.Version", out sv)) - info = CreatePlatformInfo (props); - - // Source - if (info == null && IsInParentDir (filePath, "sources")) - info = CreateSourceInfo (props); - - // System image - if (info == null && props.GetProperty ("SystemImage.Abi", out sv)) - info = CreateSystemImageInfo (props, sv); - - // Addon - if (info == null && IsInParentDir (filePath, "add-ons")) - info = CreateAddonInfo (props, filePath); - - // Extra - if (info == null && props.GetProperty ("Extra.Path", out sv)) - info = CreateExtraInfo (props); - - // Maven - if (info == null && props.GetProperty ("Maven.Version", out sv)) - info = CreateMavenInfo (props); - - // Generic - if (info == null) - info = new AndroidComponentInfoGeneric ("generic:genericDetailsType"); - - if (!String.IsNullOrEmpty (licenseId) && !String.IsNullOrEmpty (license)) - AddLicense (new License (licenseId, "text", license)); - - if (String.IsNullOrEmpty (path)) - path = GetRelativePath (filePath, sdkRoot); - - AddComponent (new RemotePackage (this, new Uri (filePath), null, errorHandler, null) { - Present = true, - Path = ConstructPackagePath (filePath, sdkRoot), - FileSystemPath = path, - Info = info, - DisplayName = displayName, - InstalledRevision = installedRevision, - Revision = installedRevision, - LicenseID = license - }); - - return true; - } - - string ConstructPackagePath (string filePath, string sdkRoot) - { - return GetRelativePath (filePath, sdkRoot)?.Replace (Path.DirectorySeparatorChar, ';'); - } - - string GetRelativePath (string filePath, string sdkRoot) - { - if (String.IsNullOrEmpty (filePath) || String.IsNullOrEmpty (sdkRoot) || filePath.Length <= sdkRoot.Length) - return null; - - return Path.GetDirectoryName (filePath).Substring (sdkRoot.Length + 1); - } - - AndroidComponentInfoMaven CreateMavenInfo (IDictionary props) - { - return new AndroidComponentInfoMaven ( - "addon:mavenType", - CreateVendor (props, "Extra.VendorId", "Extra.VendorDisplay") - ); - } - - AndroidComponentInfoExtra CreateExtraInfo (IDictionary props) - { - return new AndroidComponentInfoExtra ( - "addon:extraDetailsType", - CreateVendor (props, "Extra.VendorId", "Extra.VendorDisplay") - ); - } - - AndroidComponentInfoAddon CreateAddonInfo (IDictionary props, string propsFilePath) - { - string apiLevel; - if (!props.GetProperty ("AndroidVersion.ApiLevel", out apiLevel)) - return null; - - string codename; - props.GetProperty ("AndroidVersion.CodeName", out codename); - - PackageTag tag = CreateTag (props, "SystemImage.TagId", "Addon.NameDisplay"); - PackageVendor vendor = CreateVendor (props, "Addon.VendorId", "Addon.VendorDisplay"); - List libraries = GetAddonLibraries (Path.Combine (Path.GetDirectoryName (propsFilePath), "manifest.ini")); - - return new AndroidComponentInfoAddon ("addon:addonDetailsType", apiLevel, codename, tag, vendor, libraries); - } - - List GetAddonLibraries (string manifestIni) - { - if (!File.Exists (manifestIni)) - return null; - - // Android SDK tools read add-on manifest.ini with java.util.Properties.load(). - // This intentionally decodes escapes/continuations and skips #/! comments, unlike INI. - // Semicolons remain value delimiters, not inline comments; standalone ; lines are unused keys. - // Keep the old INI reader's encoding detection without changing other properties consumers. - var data = AndroidUtilities.ReadAndroidProperties (manifestIni, detectEncodingFromByteOrderMarks: true); - data.TryGetValue ("libraries", out string libs); - libs = libs?.Trim (); - if (String.IsNullOrEmpty (libs)) - return null; - - List libraries = null; - string[] libids = libs.Split (';'); - foreach (string lid in libids) { - string id = lid.Trim (); - if (String.IsNullOrEmpty (lid)) - continue; - data.TryGetValue (id, out string details); - AddPackageLibrary (id, details, ref libraries); - } - - return libraries; - } - - void AddPackageLibrary (string id, string details, ref List libraries) - { - string jarPath, description; - - string[] dparts = details?.Split (';'); - if (dparts.Length == 1) { - jarPath = dparts[0].Trim (); - description = id; - } else { - jarPath = dparts[0].Trim (); - description = dparts[1].Trim (); - } - - if (libraries == null) - libraries = new List (); - libraries.Add (new PackageLibrary { - Name = id, - LocalJarPath = jarPath, - Description = description - }); - } - - AndroidComponentInfoSystemImage CreateSystemImageInfo (IDictionary props, string abiName) - { - string apiLevel; - if (!props.GetProperty ("AndroidVersion.ApiLevel", out apiLevel)) - return null; - - AndroidSystemImageAbi abi; - try { - abi = AndroidUtilities.StringToAbi (abiName); - } catch (ArgumentOutOfRangeException) { - abi = AndroidSystemImageAbi.Any; - } - - string codename; - props.GetProperty ("AndroidVersion.CodeName", out codename); - - PackageTag tag = CreateTag (props, "SystemImage.TagId", "SystemImage.TagDisplay"); - PackageVendor vendor = CreateVendor (props, "Addon.VendorId", "Addon.VendorDisplay"); - - return new AndroidComponentInfoSystemImage ("sys-img:sysImgDetailsType", abi, abiName, apiLevel, codename, tag, vendor); - } - - AndroidComponentInfoSource CreateSourceInfo (IDictionary props) - { - string apiLevel; - if (!props.GetProperty ("AndroidVersion.ApiLevel", out apiLevel)) - return null; - - string codename; - props.GetProperty ("AndroidVersion.CodeName", out codename); - - return new AndroidComponentInfoSource ("sdk:sourceDetailsType", apiLevel, codename); - } - - AndroidComponentInfoPlatform CreatePlatformInfo (IDictionary props) - { - string apiLevel; - if (!props.GetProperty ("AndroidVersion.ApiLevel", out apiLevel)) - return null; - - string layoutLibApi; - if (!props.GetProperty ("Layoutlib.Api", out layoutLibApi)) - return null; - - string codename; - props.GetProperty ("Platform.CodeName", out codename); - - if (String.IsNullOrEmpty (codename)) - props.GetProperty ("AndroidVersion.CodeName", out codename); - - return new AndroidComponentInfoPlatform ("sdk:platformDetailsType", apiLevel, codename, layoutLibApi); - } - - PackageVendor CreateVendor (IDictionary props, string idKeyName, string displayKeyName) - { - return GetIdProperties (props, idKeyName, displayKeyName, out string id, out string display) ? new PackageVendor (id, display) : null; - } - - PackageTag CreateTag (IDictionary props, string idKeyName, string displayKeyName) - { - return GetIdProperties (props, idKeyName, displayKeyName, out string id, out string display) ? new PackageTag (id, display) : null; - } - - bool GetIdProperties (IDictionary props, string idKeyName, string displayKeyName, out string id, out string display) - { - display = null; - id = null; - if (String.IsNullOrEmpty (idKeyName)) - return false; - - if (props.GetProperty (idKeyName, out id) && !String.IsNullOrEmpty (id)) { - if (!String.IsNullOrEmpty (displayKeyName)) - props.GetProperty (displayKeyName, out display); - return true; - } - return false; - } - - bool IsInParentDir (string filePath, string parentDirName) - { - if (String.IsNullOrEmpty (filePath) || String.IsNullOrEmpty (parentDirName)) - return false; - - string dir = Path.Combine (Path.GetDirectoryName (filePath), ".."); - return string.Equals (parentDirName, Path.GetFileName (Path.GetFullPath (dir)), StringComparison.OrdinalIgnoreCase); - } - - void AddLicense (License license) - { - if (license == null) - return; - if (Licenses.Values.Contains (license)) - return; - Licenses[license.ID] = license; - } - - void AddComponent (IAndroidComponent component) - { - if (component == null) - return; - if (Components.Contains (component)) - return; - Components.Add (component); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/MonitorWithTotalProgress.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/MonitorWithTotalProgress.cs deleted file mode 100644 index 2918a85ef6b..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/MonitorWithTotalProgress.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Threading; -using Xamarin.Installer.AndroidSDK.Manager; - -namespace Xamarin.Installer.AndroidSDK -{ - public class MonitorWithTotalProgress : ICancellableProgressMonitor - { - float currentTaskTotalWork; - int mainComponentsCount; - float lastLoadPercentage; - const float minPercentageChange = 0.01f; - float fractionPerComponent, fractionPerSubComponent; - - public bool DisposeOnFinish => monitor is ICancellableProgressMonitor - ? ((ICancellableProgressMonitor) monitor).DisposeOnFinish - : false; - - public CancellationToken CancellationToken => monitor is ICancellableProgressMonitor - ? ((ICancellableProgressMonitor) monitor).CancellationToken - : CancellationToken.None; - - IProgressMonitor monitor; - private int subComponentsCount; - - public bool IsMonitorWithTotalProgress { get; private set; } - public int MainComponentIndex { get; set; } - public int SubComponentIndex { get; set; } - public int SubComponentsCount { get => subComponentsCount; - set { - if (value <= 0) - throw new ArgumentOutOfRangeException (); - - subComponentsCount = value; - fractionPerSubComponent = (fractionPerComponent * 0.5f) / value; - } - } - public States State { get; set; } - - public enum States - { - Download, - Install - } - - public MonitorWithTotalProgress (IProgressMonitor monitor, int mainComponentsCount) - { - if (mainComponentsCount <= 0) - throw new ArgumentOutOfRangeException (nameof (mainComponentsCount)); - - this.monitor = monitor; - this.mainComponentsCount = mainComponentsCount; - fractionPerComponent = 1f / mainComponentsCount; - IsMonitorWithTotalProgress = monitor is IProgressMonitorWithTotalProgress; - } - - public void BeginStep (string step) - { - currentTaskTotalWork = 1; - monitor.BeginStep (step); - } - - public void BeginStep (string step, long totalWork) - { - currentTaskTotalWork = totalWork; - monitor.BeginStep (step, totalWork); - } - - public void EndStep (AndroidSDKComponentInstallationResult result = null) - { - monitor.EndStep (result); - } - - public void ReportProgress (long work) - { - monitor.ReportProgress (work); - - //Console.WriteLine ("MonitorWithTotalProgress.ReportProgress.State = " + State); - - if (IsMonitorWithTotalProgress) { - var loadPercentage = ReportTotalProgress (work); - - if (lastLoadPercentage > 0.0 && Math.Abs (lastLoadPercentage - loadPercentage) <= minPercentageChange) - return; - - lastLoadPercentage = loadPercentage; - ((IProgressMonitorWithTotalProgress) monitor).ReportTotalProgress (loadPercentage, - mainComponentsCount, MainComponentIndex, - subComponentsCount, SubComponentIndex); - } - } - - float ReportTotalProgress (long work) - { - // [ MainComponent1 ][ MainComponent2 ] ... [ MainComponentN ] - // MainComponent Installation consists of archives download: [ Archive1 ][ Archive2 ] ... [ ArchiveM ] - // and then their installation: [ Archive1 ][ Archive2 ] ... [ ArchiveM ] - // so we map MainComponentProgress as download 0 .. 50, install 50 .. 100 - // - // MainComponentDownload = (Archive1DownloadBytes / Archive1DownloadTotalBytes -> 0 .. 100) (Archive2DownloadBytes / Archive2DownloadTotalBytes -> 0 .. 100) ... (ArchiveMDownloadBytes / ArchiveMDownloadTotalBytes -> 0 .. 100) - // - // and then map each maincomponent to total progress as - // 0 .. 100 -> 1/MainComponentsCount * MainComponentIndex .. 1/MainComponentsCount * (MainComponentIndex + 1) - - float totalProgress; - float currentTaskProgress = 1f * work / currentTaskTotalWork; // 0 .. 1 - - float subComponentsProgress = SubComponentIndex * fractionPerSubComponent + currentTaskProgress * fractionPerSubComponent; - - if (State == States.Download) - totalProgress = MainComponentIndex * fractionPerComponent + subComponentsProgress; // 0 .. 50 (of local main component' progress) - else - totalProgress = MainComponentIndex * fractionPerComponent + fractionPerComponent / 2f + subComponentsProgress; // 50 .. 100 (of local main component' progress) - - return totalProgress; - } - - public void ReportMessage (string message) - { - monitor.ReportMessage (message); - } - - public void ReportError (string message, Exception ex) - { - monitor.ReportError (message, ex); - } - - public void Dispose () - { - if (monitor is ICancellableProgressMonitor) - ((ICancellableProgressMonitor) monitor)?.Dispose (); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/ParserErrorLevel.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/ParserErrorLevel.cs deleted file mode 100644 index 9cbb8fc7e1f..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/ParserErrorLevel.cs +++ /dev/null @@ -1,38 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// Copyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; - -namespace Xamarin.Installer.AndroidSDK -{ - /// - /// Parser error level. - /// - public enum ParserErrorLevel - { - /// - /// Debug - /// - Debug, - - /// - /// Info - /// - Info, - - /// - /// Warning - /// - Warning, - - /// - /// Error - /// - Error - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Repository.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Repository.cs deleted file mode 100644 index 4b6ec7d8bcf..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Repository.cs +++ /dev/null @@ -1,347 +0,0 @@ -// -// Authors: -// Marek Habersack -// -// opyright (c) 2017, Microsoft Corp. (http://microsoft.com) -// -// All rights reserved. -// -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml.Linq; -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK -{ - public abstract class Repository - { - public string Name { get; } - public Uri ManifestURL { get; protected set; } - public IList Components { get; } - public IList JdkComponents { get; } = new List(); - public bool Parsed { get; protected set; } - public IDictionary Licenses { get; } - public IDictionary Channels { get; protected set; } - public Channel DefaultChannel { get; protected set; } - public Dictionary Namespaces { get; protected set; } - - /// - /// The repository is considered Offline if manifest failed to download. - /// - /// - public bool IsOffline { get; protected set; } - - /// - /// Used to cache and retrieve cached manifest. - /// - /// - protected ILocalManifestProvider ManifestCacher { get; set; } - - protected Repository(string name, Uri manifestURL) : this(name) - { - ManifestURL = manifestURL ?? throw new ArgumentNullException(nameof(manifestURL)); - } - - protected Repository(string name) - { - Components = new List(); - Licenses = new Dictionary(StringComparer.Ordinal); - Channels = new Dictionary(StringComparer.Ordinal); - Name = String.IsNullOrEmpty(name) ? "Unnamed Repository" : name; - } - - public void Remove(IAndroidComponent component, string androidSDKRoot) - { - if (component == null) - throw new ArgumentNullException(nameof(component)); - - androidSDKRoot = androidSDKRoot?.Trim(); - if (String.IsNullOrEmpty(androidSDKRoot)) - throw new ArgumentException("must not be null or empty", nameof(androidSDKRoot)); - - var rp = EnsureBasePackage(component); - Logger.Info($"Removing Android SDK component: {rp.DetailedDescription} ({rp.Path})"); - rp.Remove(androidSDKRoot); - } - - public void Install(IAndroidComponent component, string archivePath, string androidSDKRoot, - InstallationProgressEventArgs.InstallationProgressActionDelegate progressCallback = null) - { - if (component == null) - throw new ArgumentNullException(nameof(component)); - - archivePath = archivePath?.Trim(); - if (String.IsNullOrEmpty(archivePath)) - throw new ArgumentException("must not be null or empty", nameof(archivePath)); - - androidSDKRoot = androidSDKRoot?.Trim(); - if (String.IsNullOrEmpty(androidSDKRoot)) - throw new ArgumentException("must not be null or empty", nameof(androidSDKRoot)); - - InstallComponent(component, archivePath, androidSDKRoot, progressCallback); - } - - protected virtual void InstallComponent(IAndroidComponent component, string archivePath, string androidSDKRoot, - InstallationProgressEventArgs.InstallationProgressActionDelegate progressCallback = null) - { - var rp = EnsureBasePackage(component); - Logger.Info($"Installing Android SDK component: {rp.DetailedDescription} ({rp.Path})"); - try - { - rp.Install(archivePath, androidSDKRoot, progressCallback); - } - catch (Exception ex) - { - Logger.Exception($"Installation of Android SDK component '{rp.DetailedDescription}' failed with exception.", ex); - if (component.IgnoreFailure) - Logger.Info($"Ignoring exception for Android SDK component '{rp.DetailedDescription}' - it is not critical for development."); - else - throw; - } - } - - public void Detect(AndroidSdkInstance sdkInstance) - { - if (sdkInstance == null) - throw new ArgumentNullException(nameof(sdkInstance)); - - sdkInstance.Components = Components.Where(c => c != null).Select(c => c.Clone()).ToList(); - DetectInternal(sdkInstance); - } - - public void Refresh(AndroidSdkInstance sdkInstance) - { - if (sdkInstance == null) - throw new ArgumentNullException(nameof(sdkInstance)); - - if (Components == null || Components.Count == 0 || sdkInstance.Components == null | sdkInstance.Components.Count == 0) - return; - - foreach (IAndroidComponent c in Components) - { - if (c == null) - continue; - - IAndroidComponent match = FindMatchedComponent(c, sdkInstance.Components); - - if (match == null) - { - sdkInstance.Components.Add(c); - continue; - } - - BasePackage remotePackage = EnsureBasePackage(c); - BasePackage instancePackage = EnsureBasePackage(match); - instancePackage.PerformDetection(sdkInstance.Path, true); - instancePackage.RefreshMetadata(remotePackage); - } - - var componentsToRemove = sdkInstance.Components - .Where(c => FindMatchedComponent(c, Components) == null) - .ToArray(); - foreach (var c in componentsToRemove) - sdkInstance.Components.Remove(c); - } - - IAndroidComponent FindMatchedComponent(IAndroidComponent c, IList componentList) - { - return componentList.FirstOrDefault(component => component?.MatchesTo(c) == true); - } - - BasePackage EnsureBasePackage(IAndroidComponent c) - { - var ret = c as BasePackage; - if (ret == null) - throw new InvalidOperationException($"Internal error: unsupported component type {c.GetType()}"); - - return ret; - } - - protected virtual void DetectInternal(AndroidSdkInstance sdkInstance) - { - if (sdkInstance.Components.Count == 0) - { - Logger.Info($"Unable to perform detection in '{Name}', no known components"); - return; - } - - foreach (IAndroidComponent c in sdkInstance.Components) - { - DetectComponent(sdkInstance, c); - } - } - - protected virtual void DetectComponent(AndroidSdkInstance sdkInstance, IAndroidComponent c) - { - EnsureBasePackage(c)?.PerformDetection(sdkInstance.Path); - } - - public Channel GetChannel(string channelId) - { - return GetDictionaryEntry(Channels, channelId); - } - - public License GetLicense(string licenseId) - { - return GetDictionaryEntry(Licenses, licenseId); - } - - protected T GetDictionaryEntry(IDictionary dict, string entryId) where T : class - { - if (dict == null) - return null; - - entryId = entryId?.Trim(); - if (String.IsNullOrEmpty(entryId)) - return null; - - T ret; - if (!dict.TryGetValue(entryId, out ret)) - return null; - - return ret; - } - - protected void CopyDictionary(IDictionary source, IDictionary destination) - { - if (source == null) - return; - if (destination == null) - throw new ArgumentNullException(nameof(destination)); - - destination.Clear(); - foreach (var kvp in source) - destination.Add(kvp.Key, kvp.Value); - } - - public string GetNamespaceUri(string nsName) - { - if (String.IsNullOrEmpty(nsName) || Namespaces == null) - return String.Empty; - - XNamespace ns; - if (Namespaces.TryGetValue(nsName, out ns) && ns != null) - return ns.NamespaceName ?? String.Empty; - - return String.Empty; - } - - public abstract void Parse(); - - /// - /// Loads online manifest using ManifestURL; - /// If it fails, tries to load local cached manifest; - /// If local manifest is loaded, sets IsOffline to true and returns it. - /// - /// - protected string LoadManifest() - { - string manifest = null; - Exception exception = null; - try - { - if (CommonUtilities.Helpers.DownloadToString(ManifestURL, out manifest) && manifest != null) - { - IsOffline = false; - ManifestCacher?.SaveManifest(manifest); - return manifest; - } - - } - catch (Exception ex) - { - exception = ex; - } - - // In case something throwed during manifest caching. - if (manifest != null) - return manifest; - - IsOffline = true; - Logger.Error($"Failed to download {Name} manifest from {ManifestURL}. {exception}"); - - // If download from primary URL fails, attempt to use cached manifest - if (ManifestCacher != null) - { - Logger.Info("Trying to load cached manifest..."); - - manifest = ManifestCacher.GetManifest(); - if (manifest != null) - { - Logger.Info("Using cached manifest..."); - return manifest; - } - else - { - Logger.Info("Unable to use cached manifest."); - } - } - - // If both primary URL and cached manifest fail, try fallback URL - var fallbackUrl = GetFallbackManifestUrl(); - if (fallbackUrl != null) - { - Logger.Info("Trying to load fallback manifest..."); - if (CommonUtilities.Helpers.DownloadToString(fallbackUrl, out manifest) && manifest != null) - { - - IsOffline = false; - Logger.Info("Successfully loaded the fallback manifest file"); - return manifest; - } - } - if (exception != null) - throw exception; - - return null; - } - - /// - /// Parses manifest xml string into XDocument; - /// Re-throws if XDocument.Load throws; - /// Logs manfiest if the parsing failes. - /// - /// - /// - /// Returns XDocument - protected XDocument ParseManifest(string manifestName, string manifest) - { - using (System.IO.Stream input = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(manifest))) - { - return ParseManifest(manifestName, input); - } - } - - /// - /// Parses manifest xml stream into XDocument; - /// Re-throws if XDocument.Load throws; - /// Logs manfiest if the parsing failes. - /// - /// - /// - /// - /// Returns XDocument - protected XDocument ParseManifest(string manifestName, System.IO.Stream manifestStream, LoadOptions loadOptions = LoadOptions.None) - { - try - { - return XDocument.Load(manifestStream, LoadOptions.SetLineInfo); - } - catch (Exception ex) - { - Logger.Exception($"Could not parse {manifestName} xml. For more info, check the logged manifest file", ex); - - Logger.LogManifest(manifestName, manifestStream); - throw; - } - } - - public virtual Uri GetFallbackManifestUrl() - { - return null; - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Xamarin/XamarinPackage.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Xamarin/XamarinPackage.cs deleted file mode 100644 index bc55f72d54b..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Xamarin/XamarinPackage.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Xml; - -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK.Xamarin -{ - class XamarinPackage : BasePackage, IEquatable - { - public override Channel Channel => Repository.GetChannel ("channel-0"); - public override AndroidComponentType ComponentType { get; } - public Uri OriginalManifestUri { get; set; } - - public XamarinPackage (Repository repository, Uri manifestURL, IXmlLineInfo location, IList archives, AndroidComponentType componentType) : base (repository, manifestURL, location, archives) - { - ComponentType = componentType; - PopulatePlatformArchives (false); - } - - public static XamarinPackage Clone (XamarinPackage source) - { - if (source == null) - return null; - - // Archive instance aren't cloned because we want them to be shared amongst all the SDK instances and as the list is read-only, there's no - // need to clone it either. - return new XamarinPackage (source.Repository, source.ManifestURL, source.Location, source.OriginalArchives, source.ComponentType) { - IsEssential = source.IsEssential, - IgnoreFailure = source.IgnoreFailure, - Present = source.Present, - NeedsUpdate = source.NeedsUpdate, - Path = source.Path, - FileSystemPath = source.FileSystemPath, - Obsolete = source.Obsolete, - Info = source.Info, - Revision = source.Revision, - InstalledRevision = source.InstalledRevision, - DisplayName = source.DisplayName, - Dependencies = source.Dependencies, - LicenseID = source.LicenseID, - ForceInstallation = source.ForceInstallation - }; - } - - public override void RefreshMetadata (IAndroidComponent component, bool ignoreInstalledState = true) - { - RefreshMetadata (component as XamarinPackage); - } - - void RefreshMetadata (XamarinPackage rp, bool ignoreInstalledState = true) - { - if (rp == null) - throw new ArgumentNullException (nameof (rp)); - - MetadataChanged (CreateMetadata (rp), true, ignoreInstalledState); - } - - protected override PackageMetadata CreateMetadata (BasePackage component) - { - return new PackageMetadata (component); - } - - public bool Equals (XamarinPackage other) - { - if (other == null) - return false; - - return base.Equals (other as BasePackage); - } - - public override bool Equals (object obj) - { - return Equals (obj as XamarinPackage); - } - - public override int GetHashCode () - { - return base.GetHashCode (); - } - - protected override void LogError (string message) - { - Logger.Error (message); - } - - protected override void LogWarning (string message) - { - Logger.Warning (message); - } - - protected override void LogInfo (string message) - { - Logger.Info (message); - } - - protected override void LogDebug (string message) - { - Logger.Debug (message); - } - } -} diff --git a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Xamarin/XamarinRepository.cs b/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Xamarin/XamarinRepository.cs deleted file mode 100644 index 93da5ed5036..00000000000 --- a/src/Xamarin.Installer.AndroidSDK/Xamarin.Installer.AndroidSDK/Xamarin/XamarinRepository.cs +++ /dev/null @@ -1,374 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Xml.Linq; -using System.Xml.XPath; -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.Common; - -namespace Xamarin.Installer.AndroidSDK.Xamarin -{ - class XamarinRepository : Repository - { - readonly Dictionary> infoParsers; - readonly Dictionary infoToComponentType; - - public XamarinRepository(Uri manifestURL = null, bool cacheManifest = false) : base("Xamarin Repository") - { - this.ManifestURL = manifestURL ?? GetDefaultManifestURL(); - - infoParsers = new Dictionary> { - [typeof (AndroidComponentInfoPlatform)] = ParsePlatformPackageInfo, - [typeof (AndroidComponentInfoSystemImage)] = ParseSystemImageInfo, - [typeof (AndroidComponentInfoAddon)] = ParseAddonInfo, - [typeof (AndroidComponentInfoExtra)] = ParseExtraInfo, - }; - - infoToComponentType = new Dictionary { - [typeof (AndroidComponentInfoPlatform)] = AndroidComponentType.Platform, - [typeof (AndroidComponentInfoSystemImage)] = AndroidComponentType.SystemImage, - [typeof (AndroidComponentInfoAddon)] = AndroidComponentType.Addon, - [typeof (AndroidComponentInfoExtra)] = AndroidComponentType.Extra, - }; - - var defaultChannel = new Channel("channel-0", "stable"); - DefaultChannel = defaultChannel; - Channels.Add("channel-0", defaultChannel); - - if (cacheManifest) - ManifestCacher = LocalManifestProvider.CreateXamarinManifestProvider(); - } - - Uri GetDefaultManifestURL() - { - Logger.Debug($"Android Manifest Version: {Constants.RequiredComponentVersions.AndroidManifestFeedVersion}"); - var androidManifestFeedVersion = Constants.RequiredComponentVersions.AndroidManifestFeedVersion?.Replace(".", "-"); - return new Uri($"https://aka.ms/AndroidManifestFeed/d{androidManifestFeedVersion}"); - } - - public override void Parse() - { - ParseInternal(); - Parsed = true; - } - - void ParseInternal() - { - string manifest = LoadManifest(); - if (string.IsNullOrEmpty(manifest)) - { - Logger.Warning($"Android manifest should not be empty! Manifest URL: {ManifestURL}"); - // todo: should we throw here? - return; - } - - Uri baseURL = Helpers.GetBaseURL(ManifestURL); - Logger.Debug($"Xamarin manifest base URL: {baseURL}"); - - Components?.Clear(); - - XDocument doc = ParseManifest("XamarinAndroidManifest", manifest); - - var namespaces = new Dictionary(StringComparer.Ordinal); - doc.Root.GetNamespaces(ManifestURL, ref namespaces); - Namespaces = namespaces; - - XElement root = doc.Root; - - var licenses = new Dictionary(StringComparer.Ordinal); - foreach (XElement element in root.XPathSelectElements("//license[string-length (@id) > 0]")) - { - string licenseId = element.GetAttributeValue("id", documentUrl: ManifestURL); - if (licenses.ContainsKey(licenseId)) - continue; - string licenseType = element.GetAttributeValue("type", required: false, documentUrl: ManifestURL); - licenses.Add(licenseId, new License(licenseId, licenseType, element.Value)); - } - if (licenses.Count > 0) - CopyDictionary(licenses, Licenses); - - ParsePackages("platform tools", root.XPathSelectElements("./platform-tools")); - - // Obsolete. Using for backward compatibility. - ParsePackages("tools", root.XPathSelectElements("./tools")); - - ParsePackages("cmdline-tools", root.XPathSelectElements("./cmdline-tools")); - ParsePackages("build tools", root.XPathSelectElements("./build-tool")); - ParsePackages("emulators", root.XPathSelectElements("./emulator")); - ParsePackages("NDK", root.XPathSelectElements("./ndk")); - ParsePackages("LLDB", root.XPathSelectElements("./lldb")); - ParsePackages("patchers", root.XPathSelectElements("./patcher")); - ParsePackages("platforms", root.XPathSelectElements("./platform")); - ParsePackages("system images", root.XPathSelectElements("./system-image")); - ParsePackages("addons", root.XPathSelectElements("./addon")); - ParsePackages("extras", root.XPathSelectElements("./extra")); - ParseJdkPackages(root.XPathSelectElements("./jdk")); - } - - void ParseJdkPackages(IEnumerable elements) - { - foreach (XElement element in elements) - { - JdkComponents.Add(ParseJdkPackage(element)); - } - } - - JdkPackage ParseJdkPackage(XElement element) - { - var description = element.GetAttributeValue("description", documentUrl: ManifestURL); - var vendorId = element.GetAttributeValue("vendor-id", documentUrl: ManifestURL); - var vendorDisplay = element.GetAttributeValue("vendor-display", documentUrl: ManifestURL); - var vendor = CreateVendor(vendorId, vendorDisplay); - var revision = new AndroidRevision(element.GetAttributeValue("revision", documentUrl: ManifestURL)); - string licenseId = element.GetAttributeValue("license", documentUrl: ManifestURL); - bool obsolete = element.GetAttributeValue("obsolete", documentUrl: ManifestURL).AsBool(); - bool preview = element.GetAttributeValue("preview", documentUrl: ManifestURL).AsBool(); - - var archives = new List(); - foreach (XElement urlElement in element.XPathSelectElements("./urls/url")) - { - var archive = ParseJDKArchive(urlElement); - archives.Add(archive); - } - - if (archives.Count == 0) - throw new InvalidOperationException($"Package {element.Name} at {element.GetLocation(ManifestURL)} does not have any valid URLs"); - - return new JdkPackage(description, obsolete, preview, licenseId, vendor, revision, archives); - } - - void ParsePackages(string name, IEnumerable elements) where TInfo : AndroidComponentInfo - { - Logger.Debug($"Parsing: {name}"); - if (!elements.Any()) - { - Logger.Debug("No elements of this kind found"); - return; - } - - AndroidComponentInfo info = null; - Func infoParser; - - foreach (XElement element in elements) - { - string type = element.GetAttributeValue("original-type", documentUrl: ManifestURL); - info = null; - if (infoParsers.TryGetValue(typeof(TInfo), out infoParser) && infoParser != null) - { - info = infoParser(name, type, element); - } - - if (info == null) - info = new AndroidComponentInfoGeneric(type); - - Components.Add(ParseCommonPackageData(name, info, element)); - } - } - - XamarinPackage ParseCommonPackageData(string name, AndroidComponentInfo info, XElement element) - { - // Ignored attributes (obsolete): - // preview - // - var revision = new AndroidRevision(element.GetAttributeValue("revision", documentUrl: ManifestURL)); - string path = element.GetAttributeValue("path", documentUrl: ManifestURL); - string filesystemPath = element.GetAttributeValue("filesystem-path", documentUrl: ManifestURL); - string description = element.GetAttributeValue("description", documentUrl: ManifestURL); - string licenseId = element.GetAttributeValue("license", documentUrl: ManifestURL); - bool obsolete = element.GetAttributeValue("path", documentUrl: ManifestURL).AsBool(); - Uri originalManifestUri = element.GetAttributeValue("manifest-url", documentUrl: ManifestURL).AsUri(); - - var archives = new List(); - foreach (XElement urlElement in element.XPathSelectElements("./urls/url")) - { - archives.Add(ParseArchive(urlElement)); - } - - if (archives.Count == 0) - throw new InvalidOperationException($"Package {element.Name} at {element.GetLocation(ManifestURL)} does not have any valid URLs"); - - var dependencies = new List(); - foreach (XElement urlElement in element.XPathSelectElements("./dependencies/dependency")) - { - Dependency dep = ParseDependency(urlElement); - if (dep.Platform != AndroidSDKPlatform.Any && dep.Platform != AndroidSDKPlatform.Unknown && dep.Platform != AndroidSDKContext.Instance.Platform) - continue; - dependencies.Add(dep); - } - if (dependencies.Count == 0) - dependencies = null; - - AndroidComponentType componentType; - if (!infoToComponentType.TryGetValue(info.GetType(), out componentType)) - componentType = AndroidComponentType.Generic; - - return new XamarinPackage(this, ManifestURL, element.GetLineInfo(), archives, componentType) - { - Revision = revision, - Path = path, - FileSystemPath = filesystemPath, - DisplayName = description, - Obsolete = obsolete, - OriginalManifestUri = originalManifestUri, - LicenseID = licenseId, - Info = info, - Dependencies = dependencies, - }; - } - - Dependency ParseDependency(XElement element) - { - string path = element.GetAttributeValue("path", documentUrl: ManifestURL); - string minRevision = element.GetAttributeValue("min-revision", documentUrl: ManifestURL); - string hostOS = element.GetAttributeValue("host-os", documentUrl: ManifestURL); - - return new Dependency(path, String.IsNullOrEmpty(minRevision) ? null : new AndroidRevision(minRevision)) - { - Platform = String.IsNullOrEmpty(hostOS) ? AndroidSDKPlatform.Unknown : AndroidUtilities.GetPlatformFromOS(hostOS) - }; - } - - JdkArchive ParseJDKArchive(XElement element) - { - string payloadFileName = element.GetAttributeValue("payloadFileName", documentUrl: ManifestURL); - var archive = ParseArchive(element); - archive.PayloadFileName = payloadFileName; - return archive; - } - - T ParseArchive(XElement element) where T : ArchiveBase - { - ulong size = element.GetAttributeValue("size", documentUrl: ManifestURL).AsULong(); - string checksum = element.GetAttributeValue("checksum", documentUrl: ManifestURL); - string checksumType = element.GetAttributeValue("checksum-type", required: false, documentUrl: ManifestURL); - string hostOS = element.GetAttributeValue("host-os", documentUrl: ManifestURL); - string hostArch = element.GetAttributeValue("host-arch", required: false, documentUrl: ManifestURL); - uint hostBits = element.GetAttributeValue("host-bits", documentUrl: ManifestURL).AsUInt(); - Uri url = element.GetElementValue().AsUri(true); - - var archive = (T)Activator.CreateInstance(typeof(T), new object[] { hostOS }); - archive.Size = size; - archive.Checksum = checksum; - archive.ChecksumType = checksumType; - archive.HostArch = hostArch; - archive.HostBits = hostBits; - archive.Url = url; - - return archive; - } - - AndroidComponentInfo ParsePlatformPackageInfo(string name, string packageType, XElement element) - { - // Ignored attributes (obsolete): - // min-tools-rev - // layoutlib-revision - // - string apiLevel = element.GetAttributeValue("api", documentUrl: ManifestURL); - string codeName = element.GetAttributeValue("codename", documentUrl: ManifestURL); - string layoutLibApi = element.GetAttributeValue("layoutlib-api", documentUrl: ManifestURL); - string description = element.GetAttributeValue("description", documentUrl: ManifestURL); - string preview = element.GetAttributeValue("preview", documentUrl: ManifestURL); - - return new AndroidComponentInfoPlatform("platform", apiLevel, codeName, layoutLibApi) - { - Description = description, - Preview = preview != "False", - }; - } - - AndroidComponentInfo ParseSystemImageInfo(string name, string packageType, XElement element) - { - string apiLevel = element.GetAttributeValue("api", documentUrl: ManifestURL); - string abi = element.GetAttributeValue("abi", documentUrl: ManifestURL); - string codeName = element.GetAttributeValue("codename", documentUrl: ManifestURL); - string tagId = element.GetAttributeValue("tag-id", documentUrl: ManifestURL); - string tagDisplay = element.GetAttributeValue("tag-display", documentUrl: ManifestURL); - string vendorId = element.GetAttributeValue("vendor-id", documentUrl: ManifestURL); - string vendorDisplay = element.GetAttributeValue("vendor-display", documentUrl: ManifestURL); - - return new AndroidComponentInfoSystemImage( - packageType, - AndroidUtilities.StringToAbi(abi), - abi, - apiLevel, - codeName, - CreateTag(tagId, tagDisplay), - CreateVendor(vendorId, vendorDisplay) - ); - } - - AndroidComponentInfo ParseAddonInfo(string name, string packageType, XElement element) - { - string apiLevel = element.GetAttributeValue("api", documentUrl: ManifestURL); - string codeName = element.GetAttributeValue("codename", documentUrl: ManifestURL); - string tagId = element.GetAttributeValue("tag-id", documentUrl: ManifestURL); - string tagDisplay = element.GetAttributeValue("tag-display", documentUrl: ManifestURL); - string vendorId = element.GetAttributeValue("vendor-id", documentUrl: ManifestURL); - string vendorDisplay = element.GetAttributeValue("vendor-display", documentUrl: ManifestURL); - - var libraries = new List(); - foreach (XElement libElement in element.XPathSelectElements("./libraries/library")) - { - libraries.Add(ParseLibrary(libElement)); - } - - return new AndroidComponentInfoAddon( - packageType, - apiLevel, - codeName, - CreateTag(tagId, tagDisplay), - CreateVendor(vendorId, vendorDisplay), - libraries - ); - } - - PackageLibrary ParseLibrary(XElement element) - { - string name = element.GetAttributeValue("name", documentUrl: ManifestURL); - string localJarPath = element.GetAttributeValue("local-jar-path", documentUrl: ManifestURL); - string description = element.GetAttributeValue("description", documentUrl: ManifestURL); - - return new PackageLibrary - { - Name = name, - LocalJarPath = localJarPath, - Description = description - }; - } - - AndroidComponentInfo ParseExtraInfo(string name, string packageType, XElement element) - { - string vendorId = element.GetAttributeValue("vendor-id", documentUrl: ManifestURL); - string vendorDisplay = element.GetAttributeValue("vendor-display", documentUrl: ManifestURL); - - return new AndroidComponentInfoExtra(packageType, CreateVendor(vendorId, vendorDisplay)); - } - - PackageTag CreateTag(string id, string display) - { - if (String.IsNullOrEmpty(id)) - return null; - - return new PackageTag(id, display); - } - - PackageVendor CreateVendor(string id, string display) - { - if (String.IsNullOrEmpty(id)) - return null; - - return new PackageVendor(id, display); - } - - public override Uri GetFallbackManifestUrl() - { - Logger.Debug($"Fallback Android Manifest Version: {Constants.RequiredComponentVersions.AndroidManifestFeedVersion}"); - var dirPathParent = new Uri(typeof(XamarinRepository).Assembly.Location); - var manifestUri = new Uri(dirPathParent, $"AndroidManifestFeed_d{Constants.RequiredComponentVersions.AndroidManifestFeedVersion}.xml"); - - Logger.Debug($"Fallback Manifest Url:: manifestUri: {manifestUri}"); - return manifestUri; - } - } -} diff --git a/src/Xamarin.Installer.Build.Tasks/JavaDependencyInstaller.cs b/src/Xamarin.Installer.Build.Tasks/JavaDependencyInstaller.cs new file mode 100644 index 00000000000..5f3a4fbbf2e --- /dev/null +++ b/src/Xamarin.Installer.Build.Tasks/JavaDependencyInstaller.cs @@ -0,0 +1,121 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net.Http; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Xamarin.Android.Tools; + +namespace Xamarin.Installer.Build.Tasks +{ + /// + /// A simplified copy of JavaDependencyInstaller from the removed Xamarin.Installer.AndroidSDK project. + /// It downloads the JDK from aka.ms/download-jdk in place of the Xamarin manifest, and it extracts the + /// archive next to JdkPath in place of %TEMP%. + /// + public class JavaDependencyInstaller + { + public string JdkPath { get; set; } + + public async Task GetFirstValidJdkArchiveWithVersion (HttpClient httpClient, string version, CancellationToken cancellationToken) + { + string os = RuntimeInformation.IsOSPlatform (OSPlatform.Windows) ? "windows" : RuntimeInformation.IsOSPlatform (OSPlatform.OSX) ? "macOS" : RuntimeInformation.IsOSPlatform (OSPlatform.Linux) ? "linux" : null; + string arch = RuntimeInformation.OSArchitecture switch { + Architecture.X64 => "x64", + Architecture.Arm64 => "aarch64", + _ => null, + }; + if (os == null || arch == null) + return null; + string extension = RuntimeInformation.IsOSPlatform (OSPlatform.Windows) ? "zip" : "tar.gz"; + var url = new Uri ($"https://aka.ms/download-jdk/microsoft-jdk-{version}-{os}-{arch}.{extension}"); + + // aka.ms sends an unknown link to an HTML page on bing.com with status 200, so an HTML response means that this JDK version does not exist. + using (var response = await httpClient.GetAsync (url, HttpCompletionOption.ResponseHeadersRead, cancellationToken)) { + if (!response.IsSuccessStatusCode || response.Content.Headers.ContentType?.MediaType == "text/html") + return null; + } + return new Archive { Url = url }; + } + + public bool GetJdkRevision (out Version version) + { + if (string.IsNullOrEmpty (JdkPath)) { + version = new Version (0, 0); + return false; + } + var javaVersion = InstallAndroidDependencies.ReadProperty (Path.Combine (JdkPath, "release"), "JAVA_VERSION"); + bool foundUnparsedVersion = javaVersion != null; + javaVersion = javaVersion?.Replace ("\"", string.Empty).Replace ("'", string.Empty); + version = InstallAndroidDependencies.ParseVersion (javaVersion) ?? new Version (0, 0); + return foundUnparsedVersion && version != new Version (0, 0); + } + + public bool IsJdkPathValid () + { + if (string.IsNullOrEmpty (JdkPath)) { + return false; + } + + // If the requested path is in a known VS installation Program Files path on Windows, request a different path + if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) { + if (JdkPath.StartsWith (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles), StringComparison.OrdinalIgnoreCase) + || JdkPath.StartsWith (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86), StringComparison.OrdinalIgnoreCase)) { + return false; + } + } + + // If the requested path is not writable, request a different path + try { + Directory.CreateDirectory (JdkPath); + using var _ = File.Create (Path.Combine (JdkPath, "tmp"), 1, FileOptions.DeleteOnClose); + } catch (Exception) { + return false; + } + + return true; + } + + public async Task InstallJdk (Archive archive, CancellationToken cancellationToken) + { + // The original code extracted into %TEMP%. Extract next to JdkPath instead, because Directory.Move + // fails when %TEMP% and JdkPath are on different volumes. + var unzipDestination = Path.GetFullPath (JdkPath).TrimEnd (Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + "." + Path.GetRandomFileName (); + Directory.CreateDirectory (unzipDestination); + + try { + if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) { + ZipFile.ExtractToDirectory (archive.DownloadedFilePath, unzipDestination); + } else { + var tar = ProcessUtils.CreateProcessStartInfo ("/usr/bin/tar", "-xzf", archive.DownloadedFilePath); + tar.WorkingDirectory = unzipDestination; + var extractResult = new InstallAndroidDependencies.OutputTail (); + int exitCode = await ProcessUtils.StartProcess (tar, extractResult, extractResult, cancellationToken); + if (exitCode != 0) + throw new Exception ($"Failed to extract temp Java SDK archive {archive.DownloadedFilePath}:\n{extractResult}"); + } + + var jdkSubDir = Directory.GetDirectories (unzipDestination).FirstOrDefault (); + if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) { + jdkSubDir = Path.Combine (jdkSubDir, "Contents", "Home"); + } + // Keep the existing JDK if the build was canceled during extraction. + cancellationToken.ThrowIfCancellationRequested (); + RemoveJdk (); + Directory.Move (jdkSubDir, JdkPath); + } finally { + if (Directory.Exists (unzipDestination)) + Directory.Delete (unzipDestination, true); + } + } + + public void RemoveJdk () + { + if (Directory.Exists (JdkPath)) + Directory.Delete (JdkPath, true); + } + + } +} \ No newline at end of file diff --git a/src/Xamarin.Installer.Build.Tasks/Properties/Resources.Designer.cs b/src/Xamarin.Installer.Build.Tasks/Properties/Resources.Designer.cs index 65efd4b57bd..10855e20362 100644 --- a/src/Xamarin.Installer.Build.Tasks/Properties/Resources.Designer.cs +++ b/src/Xamarin.Installer.Build.Tasks/Properties/Resources.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -60,22 +60,31 @@ internal Resources() { } } - internal static string XA5305 { + internal static string XA5306 { get { - return ResourceManager.GetString("XA5305", resourceCulture); + return ResourceManager.GetString("XA5306", resourceCulture); } } - - /// - /// Looks up a localized string similar to Failed to locate Android SDK at path `{0}`.. - /// - internal static string AndroidSdk_Not_Found { + internal static string XA5307 { get { - return ResourceManager.GetString("AndroidSdk_Not_Found", resourceCulture); + return ResourceManager.GetString("XA5307", resourceCulture); } } - + + internal static string XA5308 { + get { + return ResourceManager.GetString("XA5308", resourceCulture); + } + } + + internal static string XA5305 { + get { + return ResourceManager.GetString("XA5305", resourceCulture); + } + } + + /// /// Looks up a localized string similar to The path to the Android SDK has not been set. Either provide the '-p:AndroidSdkDirectory' MSbuild property with a valid path or set the 'ANDROID_HOME' or 'ANDROID_SDK_ROOT' environment variables and try again.. /// @@ -114,34 +123,16 @@ internal static string Invalid_JavaSdkVersion { } /// - /// Looks up a localized string similar to The Android SDK license agreements were not accepted, please set `$(AcceptAndroidSDKLicenses)` to accept.. + /// Looks up a localized string similar to The Android SDK license agreements were not accepted. Read the Android SDK License Agreement at https://developer.android.com/studio/terms, then set `$(AcceptAndroidSDKLicenses)` to `true` to accept it.. /// internal static string License_Not_Accepted { get { return ResourceManager.GetString("License_Not_Accepted", resourceCulture); } } - - /// - /// Looks up a localized string similar to an error occurred trying to accept the Android SDK licenses. {0}. - /// - internal static string Licenses_Acceptance_Failed { - get { - return ResourceManager.GetString("Licenses_Acceptance_Failed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Internal error: expected to install {0} components, but no downloads were available.. - /// - internal static string Required_Downloadable_Mismatch { - get { - return ResourceManager.GetString("Required_Downloadable_Mismatch", resourceCulture); - } - } - + /// - /// Looks up a localized string similar to Dependency `{0}` should have been installed but could not be resolved. You can attempt to install it with: `{1} --install "{0}"`. + /// Looks up a localized string similar to The Android CLI did not install Android SDK package `{0}` into `{1}`. Make sure that the package name and version are correct.. /// internal static string Required_Not_Installed { get { @@ -166,14 +157,5 @@ internal static string Task_Failed { return ResourceManager.GetString("Task_Failed", resourceCulture); } } - - /// - /// Looks up a localized string similar to `$(AndroidManifestType)` value of `{0}` is not supported. Defaulting to `Xamarin`.. - /// - internal static string Unsupported_Manifest_Type { - get { - return ResourceManager.GetString("Unsupported_Manifest_Type", resourceCulture); } - } - } } diff --git a/src/Xamarin.Installer.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Installer.Build.Tasks/Properties/Resources.resx index 91e85456bf2..9dbd765c459 100644 --- a/src/Xamarin.Installer.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Installer.Build.Tasks/Properties/Resources.resx @@ -1,4 +1,4 @@ - + + + <_AndroidCliVersion>1.1.16717390 + <_AndroidCliBaseUrl>https://dl.google.com/android/cli/$(_AndroidCliVersion) + + <_AndroidCliDirectory Condition="$([MSBuild]::IsOSPlatform('Windows'))">$(LocalAppData)\dotnet-android\AndroidCli\$(_AndroidCliVersion)\ + <_AndroidCliDirectory Condition="$([MSBuild]::IsOSPlatform('OSX'))">$(HOME)/Library/Caches/dotnet-android/AndroidCli/$(_AndroidCliVersion)/ + <_AndroidCliDirectory Condition="'$(_AndroidCliDirectory)'==''">$(HOME)/.cache/dotnet-android/AndroidCli/$(_AndroidCliVersion)/ + + + <_AndroidCliPackage Include="windows_x86_64" Url="$(_AndroidCliBaseUrl)/windows_x86_64/android-cli.exe" Sha256="E461A361540882A759031DD94AD4814B0BA109183CDFDF18013B639539A9AF7B" /> + <_AndroidCliPackage Include="linux_x86_64" Url="$(_AndroidCliBaseUrl)/linux_x86_64/android-cli" Sha256="B34ED0BAEEFFA2AAEE2720D82491B975835696E2E56840449078BEC885436564" /> + <_AndroidCliPackage Include="linux_arm64" Url="$(_AndroidCliBaseUrl)/linux_arm64/android-cli" Sha256="42F1FB9373A398CE72B65FA1D73DDCB6B7A419ABDF45CF0A293B51BEA1288EA5" /> + <_AndroidCliPackage Include="darwin_x86_64" Url="$(_AndroidCliBaseUrl)/darwin_x86_64/android-cli" Sha256="4F102562A8D7ACA32FFE59FD9002D05EC0964675EDF17E7AC3E4C70546F30DD9" /> + <_AndroidCliPackage Include="darwin_arm64" Url="$(_AndroidCliBaseUrl)/darwin_arm64/android-cli" Sha256="E9C6E19F5ED8142E2897E0B68B476E1768633E5740AA54BFC234767CC26401FE" /> + diff --git a/src/Xamarin.Installer.Common/Properties/AssemblyInfo.cs b/src/Xamarin.Installer.Common/Properties/AssemblyInfo.cs deleted file mode 100644 index f20efb8e465..00000000000 --- a/src/Xamarin.Installer.Common/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Xamarin Android SDK Installer Common")] -[assembly: AssemblyDescription("Xamarin Android SDK Installer Common")] -[assembly: AssemblyProduct("Xamarin Android SDK Manager")] -[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] diff --git a/src/Xamarin.Installer.Common/Properties/AssemblyInfoTemplate.cs b/src/Xamarin.Installer.Common/Properties/AssemblyInfoTemplate.cs deleted file mode 100644 index d5e404adb22..00000000000 --- a/src/Xamarin.Installer.Common/Properties/AssemblyInfoTemplate.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Reflection; - -[assembly: AssemblyCopyright("Copyright © Microsoft 2020")] -[assembly: AssemblyCompany("Microsoft")] - -[assembly: AssemblyVersion (ThisAssembly.Git.SemVer.Major + "." + ThisAssembly.Git.SemVer.Minor + "." + ThisAssembly.Git.BaseVersion.Patch + "." + ThisAssembly.Git.Commits)] - -[assembly: AssemblyFileVersion (ThisAssembly.Git.SemVer.Major + "." + ThisAssembly.Git.SemVer.Minor + "." + ThisAssembly.Git.BaseVersion.Patch + "." + ThisAssembly.Git.Commits)] - -[assembly: AssemblyInformationalVersion ( - ThisAssembly.Git.SemVer.Major + "." + - ThisAssembly.Git.SemVer.Minor + "." + - ThisAssembly.Git.BaseVersion.Patch + "." + - ThisAssembly.Git.Commits + "-" + - ThisAssembly.Git.Branch + "+" + - ThisAssembly.Git.Commit)] diff --git a/src/Xamarin.Installer.Common/Properties/AssemblyInfoTemplate.tt b/src/Xamarin.Installer.Common/Properties/AssemblyInfoTemplate.tt deleted file mode 100644 index cf3c6ce76b8..00000000000 --- a/src/Xamarin.Installer.Common/Properties/AssemblyInfoTemplate.tt +++ /dev/null @@ -1,18 +0,0 @@ -<#@ template language="C#" #> -using System; -using System.Reflection; - -[assembly: AssemblyCopyright("Copyright © Microsoft <#=DateTime.Now.Year#>")] -[assembly: AssemblyCompany("Microsoft")] - -[assembly: AssemblyVersion (ThisAssembly.Git.SemVer.Major + "." + ThisAssembly.Git.SemVer.Minor + "." + ThisAssembly.Git.BaseVersion.Patch + "." + ThisAssembly.Git.Commits)] - -[assembly: AssemblyFileVersion (ThisAssembly.Git.SemVer.Major + "." + ThisAssembly.Git.SemVer.Minor + "." + ThisAssembly.Git.BaseVersion.Patch + "." + ThisAssembly.Git.Commits)] - -[assembly: AssemblyInformationalVersion ( - ThisAssembly.Git.SemVer.Major + "." + - ThisAssembly.Git.SemVer.Minor + "." + - ThisAssembly.Git.BaseVersion.Patch + "." + - ThisAssembly.Git.Commits + "-" + - ThisAssembly.Git.Branch + "+" + - ThisAssembly.Git.Commit)] diff --git a/src/Xamarin.Installer.Common/Properties/Resources.Designer.cs b/src/Xamarin.Installer.Common/Properties/Resources.Designer.cs deleted file mode 100644 index 95e6bd6fcd1..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.Designer.cs +++ /dev/null @@ -1,90 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Xamarin.Installer.Common.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xamarin.Installer.Common.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Unable to download update.. - /// - internal static string UnableToDownloadUpdate { - get { - return ResourceManager.GetString("UnableToDownloadUpdate", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to URL format of the update is invalid.. - /// - internal static string UrlFormatInvalid { - get { - return ResourceManager.GetString("UrlFormatInvalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to URL scheme of the update is not supported.. - /// - internal static string UrlSchemeNotSupported { - get { - return ResourceManager.GetString("UrlSchemeNotSupported", resourceCulture); - } - } - } -} diff --git a/src/Xamarin.Installer.Common/Properties/Resources.cs.resx b/src/Xamarin.Installer.Common/Properties/Resources.cs.resx deleted file mode 100644 index 077561f1a8f..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.cs.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Aktualizaci nejde stáhnout. - - - Formát URL aktualizace je neplatný. - - - Schéma adresy URL aktualizace není podporováno. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.de.resx b/src/Xamarin.Installer.Common/Properties/Resources.de.resx deleted file mode 100644 index 9f48602f719..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.de.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Download des Updates nicht möglich. - - - Das URL-Format des Updates ist ungültig. - - - Das URL-Schema des Updates wird nicht unterstützt. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.es.resx b/src/Xamarin.Installer.Common/Properties/Resources.es.resx deleted file mode 100644 index e7d0ad1b62a..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.es.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - No se pudo descargar la actualización - - - El formato de dirección URL de la actualización no es válido. - - - No se admite el esquema de dirección URL de la actualización. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.fr.resx b/src/Xamarin.Installer.Common/Properties/Resources.fr.resx deleted file mode 100644 index f20adae16ed..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.fr.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Impossible de télécharger la mise à jour. - - - Le format de l’URL de la mise à jour n’est pas valide. - - - Le schéma d’URL de la mise à jour n’est pas pris en charge. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.it.resx b/src/Xamarin.Installer.Common/Properties/Resources.it.resx deleted file mode 100644 index 13ceda2771f..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.it.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Non è possibile scaricare l'aggiornamento. - - - Il formato dell'URL dell'aggiornamento non è valido. - - - Lo schema dell'URL dell'aggiornamento non è supportato. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.ja.resx b/src/Xamarin.Installer.Common/Properties/Resources.ja.resx deleted file mode 100644 index 3e59cfca712..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.ja.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 更新プログラムをダウンロードできません。 - - - 更新プログラムの URL 形式が正しくありません。 - - - 更新プログラムの URL スキームはサポートされていません。 - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.ko.resx b/src/Xamarin.Installer.Common/Properties/Resources.ko.resx deleted file mode 100644 index 9cb8a223da2..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.ko.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 업데이트를 다운로드할 수 없습니다. - - - 업데이트의 URL 형식이 잘못되었습니다. - - - 업데이트의 URL 체계가 지원되지 않습니다. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.pl.resx b/src/Xamarin.Installer.Common/Properties/Resources.pl.resx deleted file mode 100644 index 106ffac32c1..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.pl.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Nie można pobrać aktualizacji. - - - Format adresu URL aktualizacji jest nieprawidłowy. - - - Schemat adresu URL aktualizacji nie jest obsługiwany. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.pt-BR.resx b/src/Xamarin.Installer.Common/Properties/Resources.pt-BR.resx deleted file mode 100644 index 1c3bbbb3610..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.pt-BR.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Não foi possível baixar a atualização. - - - O formato do URL da atualização é inválido. - - - O esquema de URL da atualização não é compatível. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.resx b/src/Xamarin.Installer.Common/Properties/Resources.resx deleted file mode 100644 index 2680f30f420..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Unable to download update. - - - URL format of the update is invalid. - - - URL scheme of the update is not supported. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.ru.resx b/src/Xamarin.Installer.Common/Properties/Resources.ru.resx deleted file mode 100644 index 4c280f89d10..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.ru.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Не удалось загрузить обновление - - - Недопустимый формат URL-адреса обновления. - - - Схема URL-адресов обновления не поддерживается. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.tr.resx b/src/Xamarin.Installer.Common/Properties/Resources.tr.resx deleted file mode 100644 index a98b7869682..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.tr.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Güncelleştirme indirilemiyor. - - - Güncelleştirmenin URL biçimi geçersiz. - - - Güncelleştirmenin URL düzeni desteklenmiyor. - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.zh-Hans.resx b/src/Xamarin.Installer.Common/Properties/Resources.zh-Hans.resx deleted file mode 100644 index 5cc2fa7ca5c..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.zh-Hans.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 无法下载更新。 - - - 更新的 URL 格式无效。 - - - 不支持更新的 URL 方案。 - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Properties/Resources.zh-Hant.resx b/src/Xamarin.Installer.Common/Properties/Resources.zh-Hant.resx deleted file mode 100644 index aa4d9dd0846..00000000000 --- a/src/Xamarin.Installer.Common/Properties/Resources.zh-Hant.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 無法下載更新。 - - - 更新的 URL 格式無效。 - - - 不支援更新的 URL 方案。 - - \ No newline at end of file diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common.csproj b/src/Xamarin.Installer.Common/Xamarin.Installer.Common.csproj deleted file mode 100644 index ad36d3a1ce1..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common.csproj +++ /dev/null @@ -1,71 +0,0 @@ - - - - $(NoWarn);CA1305;CS1591 - - - 12 - netstandard2.0 - false - false - $(MicrosoftAndroidSdkOutDir) - - - bin\Debug\Xamarin.Installer.Common.xml - - - bin\Release\Xamarin.Installer.Common.xml - - - true - $(CodeSigningFile) - - - - AssemblyInfoTemplate.tt - True - True - - - True - True - Resources.resx - - - - - - - 1.0.0 - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - TextTemplatingFileGenerator - AssemblyInfoTemplate.cs - - - - - - - $(MSBuildThisFileDirectory)..\..\build-tools\android-platform-support\version.txt - - - - - - Microsoft400 - - - Microsoft400 - - - - diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/CommonUtilities.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/CommonUtilities.cs deleted file mode 100644 index 34aad4b7f22..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/CommonUtilities.cs +++ /dev/null @@ -1,344 +0,0 @@ -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Runtime.InteropServices; -using System.Security.AccessControl; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -using Xamarin.Installer.Common.Properties; - -namespace Xamarin.Installer.Common -{ - public static class CommonUtilities - { - const int SHORT_PATH_BUFFER_LENGTH = 1024; - - static readonly char[] invalidPathChars = Path.GetInvalidPathChars (); - - static IHelpers __helpers; - static string __productName; - - public const string MANIFEST_TYPE_PROPERTY_KEY = "ManifestType"; - public const string DONT_SHOW_REPAIR_AGAIN_KEY = "DontShowRepairAgain"; - - public static IHelpers Helpers { - get { - if (__helpers == null) - throw new InvalidOperationException ("Internal error: Helpers must be initialized!"); - return __helpers; - } - - set { - if (value == null) - throw new ArgumentNullException ("value"); - __helpers = value; - } - } - - // Used in the proxy forms - public static string ProductName { - get { - if (String.IsNullOrEmpty (__productName)) - throw new InvalidOperationException ("Internal error: ProductName must be initialized to a non-empty value"); - return __productName; - } - - set { - if (String.IsNullOrEmpty (value)) - throw new ArgumentException ("Must not be empty or null", "value"); - __productName = value; - } - } - - public static void CopyDirectory (string sourceDirName, string destDirName, bool overwrite = false) - { - MoveDirectory (sourceDirName, destDirName, false, overwrite); - } - - // Based on code from: http://foldermover.codeplex.com (Apache license) - public static void MoveDirectory (string sourceDirName, string destDirName, bool move = true, bool overwrite = false, bool createSourceDirRootAtDestination = false) - { - if (sourceDirName == null) - throw new ArgumentNullException ("sourceDirName", "The source directory cannot be null."); - if (destDirName == null) - throw new ArgumentNullException ("destDirName", "The destination directory cannot be null."); - - sourceDirName = sourceDirName.Trim (); - destDirName = destDirName.Trim (); - - if ((sourceDirName.Length == 0) || (destDirName.Length == 0)) - throw new ArgumentException ("sourceDirName or destDirName is a zero-length string."); - - if (sourceDirName.IndexOfAny (invalidPathChars) > 0) - throw new ArgumentException ("The directory contains invalid path characters.", "sourceDirName"); - - if (destDirName.IndexOfAny (invalidPathChars) > 0) - throw new ArgumentException ("The directory contains invalid path characters.", "destDirName"); - - if (createSourceDirRootAtDestination) - destDirName = Path.Combine (destDirName, Path.GetFileName (sourceDirName)); - - var sourceDir = new DirectoryInfo (sourceDirName); - var destDir = new DirectoryInfo (destDirName); - - if (!sourceDir.Exists) - throw new DirectoryNotFoundException ("The path specified by sourceDirName is invalid: " + sourceDirName); - bool destExists = destDir.Exists; - if (!overwrite && destExists) - throw new IOException ("The path specified by destDirName already exists: " + destDirName); - - if (!destExists) - Directory.CreateDirectory (destDirName); - - //Copy the files in the current directory. - FileInfo[] files = sourceDir.GetFiles (); - IHelpers helpers = Helpers; - foreach (FileInfo file in files) { - string newPath = Path.Combine (destDirName, file.Name); - if (helpers.IsSpecialFile (file.FullName)) - helpers.CopySpecialFile (file.FullName, newPath); - else - Copy (file, newPath, overwrite); - - } - - //Copy all sub directories. - DirectoryInfo[] subDirs = sourceDir.GetDirectories (); - foreach (DirectoryInfo subDir in subDirs) { - string newPath = Path.Combine (destDirName, subDir.Name); - MoveDirectory (subDir.FullName, newPath, move, overwrite); - } - - if (move) { - try { - Directory.Delete (sourceDirName, true); - } catch (Exception ex) { - // Treat the error as warning - the files got copied to the destination and this is the - // most important thing here. - Logger.Exception ("Failed to delete source directory '{0}' after copying it to '{1}'", ex, sourceDir, destDir); - Logger.Warning ("You will need to delete the source directory '{0}' manually", sourceDirName); - } - } - } - - static void Copy (FileInfo source, string target, bool overwrite) - { - if (overwrite && File.Exists (target)) - File.Delete (target); - source.CopyTo (target); - } - - public static bool DeleteDirectoryRecursively (string path, bool throwOnError = false) - { - if (String.IsNullOrEmpty (path)) { - Logger.Error ("Cannot delete directory recursively, no path given."); - if (throwOnError) - throw new ArgumentNullException ("path"); - return true; - } - if (!Directory.Exists (path)) { - Logger.Warning ("Attempt to delete a non-existing directory '{0}'", path); - if (throwOnError) - throw new ArgumentException ("Directory does not exist", "path"); - return true; - } - - try { - DoDeleteDirectoryRecursively (new DirectoryInfo (path)); - return true; - } catch (Exception ex) { - Logger.Exception ("Failed to recursively delete directory '{0}'", ex, path); - if (throwOnError) - throw; - return false; - } - } - - static void DoDeleteDirectoryRecursively (FileSystemInfo fi) - { - if (fi == null) - return; - - fi.Attributes = FileAttributes.Normal; - var di = fi as DirectoryInfo; - string kind; - if (di != null) { - kind = "directory"; - foreach (var info in di.GetFileSystemInfos ()) - DoDeleteDirectoryRecursively (info); - } else - kind = "file"; - - try { - fi.Delete (); - } catch (Exception ex) { - Logger.Exception ("Failed to delete {0} '{1}',", ex, kind, fi.FullName); - throw; - } - } - - public static string RunCommand (string command, out int exitCode, params string[] arguments) - { - return RunCommand (null, command, out exitCode, false, null, arguments); - } - - public static string RunCommand (string workingDirectory, string command, out int exitCode, params string[] arguments) - { - return RunCommand (workingDirectory, command, out exitCode, false, null, arguments); - } - - public static string RunCommand (string command, out int exitCode, bool fireAndForget, params string[] arguments) - { - return RunCommand (null, command, out exitCode, fireAndForget, null, arguments); - } - - public static string RunCommand (string workingDirectory, string command, out int exitCode, bool fireAndForget, params string[] arguments) - { - return RunCommand (workingDirectory, command, out exitCode, fireAndForget, null, arguments); - } - - public static string RunCommand (string workingDirectory, string command, out int exitCode, bool fireAndForget, Action modifyStartInfo, params string[] arguments) - { - if (String.IsNullOrEmpty (command)) - throw new ArgumentNullException ("command"); - - var si = new ProcessStartInfo (command) { - UseShellExecute = false, - CreateNoWindow = true, - }; - - if (!String.IsNullOrEmpty (workingDirectory)) - si.WorkingDirectory = workingDirectory; - - CleanEnvironment (si.EnvironmentVariables); - StringBuilder output = null; - ManualResetEvent stdout_completed = null; - ManualResetEvent stderr_completed = null; - - if (!fireAndForget) { - si.RedirectStandardOutput = true; - si.RedirectStandardError = true; - si.StandardOutputEncoding = Encoding.Default; - si.StandardErrorEncoding = Encoding.Default; - output = new StringBuilder (); - stdout_completed = new ManualResetEvent (false); - stderr_completed = new ManualResetEvent (false); - } - if (arguments != null && arguments.Length > 0) { - var sb = new StringBuilder (); - bool first = true; - foreach (string a in arguments) { - if (first) - first = false; - else - sb.Append (' '); - if (a.Any (c => Char.IsWhiteSpace (c))) - sb.AppendFormat ("\"{0}\"", a); - else - sb.Append (a); - } - si.Arguments = sb.ToString (); - } - - if (modifyStartInfo != null) { - modifyStartInfo (si); - if (!si.RedirectStandardError) - si.StandardErrorEncoding = null; - if (!si.RedirectStandardOutput) - si.StandardOutputEncoding = null; - } - - var p = new Process { - StartInfo = si - }; - p.Start (); - - if (!fireAndForget) { - if (si.RedirectStandardOutput) { - p.OutputDataReceived += (sender, e) => { - if (e.Data != null) { - lock (output) { - output.AppendLine (e.Data); - } - } else - stdout_completed.Set (); - }; - p.BeginOutputReadLine (); - } - - if (si.RedirectStandardError) { - p.ErrorDataReceived += (sender, e) => { - if (e.Data != null) { - lock (output) { - output.AppendLine (e.Data); - } - } else - stderr_completed.Set (); - }; - p.BeginErrorReadLine (); - } - - p.WaitForExit (); - if (si.RedirectStandardError) - stderr_completed.WaitOne (TimeSpan.FromSeconds (1)); - if (si.RedirectStandardOutput) - stdout_completed.WaitOne (TimeSpan.FromSeconds (1)); - - exitCode = p.ExitCode; - return output.ToString (); - } else { - if (p.HasExited) - exitCode = p.ExitCode; - else - exitCode = 0; - } - - return null; - } - - [DllImport ("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - static extern uint GetShortPathName ( - [MarshalAs (UnmanagedType.LPTStr)] string longPath, - [MarshalAs (UnmanagedType.LPTStr)] StringBuilder shortPath, - uint shortPathLength); - - public static string GetShortPath (string path) - { - if (String.IsNullOrEmpty (path)) - return path; - - if (!Directory.Exists (path) && !File.Exists (path)) - return path; - - var sb = new StringBuilder (SHORT_PATH_BUFFER_LENGTH); - try { - uint result = GetShortPathName (path, sb, SHORT_PATH_BUFFER_LENGTH); - if (result == 0) { - int error = Marshal.GetLastWin32Error (); - Logger.Warning ("failed to retrieve short path name for '{0}'. Long path form will be used instead. Error: {1}", path, error); - return path; - } - } catch (Exception ex) { - Logger.Exception ("failed to get short path name for '{0}'. Long path form will be used instead. Exception was thrown.", ex, path); - return path; - } - - return sb.ToString (); - } - - static void CleanEnvironment (StringDictionary envvars) - { - envvars.Remove ("MONO_PATH"); - envvars.Remove ("MONO_GAC_PREFIX"); - envvars.Remove ("MONOMAC_LOGDIR"); - envvars.Remove ("PKG_CONFIG_PATH"); - } - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.String.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.String.cs deleted file mode 100644 index 123a15a6c8b..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.String.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Xamarin.Installer.Common -{ - static partial class Extensions - { - public static string SafeTrim (this string s) - { - return (s ?? String.Empty).Trim (); - } - - public static string RemoveTrailingDirectorySeparator (this string path) - { - if (String.IsNullOrEmpty (path) || (!path.EndsWith (Path.DirectorySeparatorChar.ToString ()) && !path.EndsWith (Path.AltDirectorySeparatorChar.ToString ()))) - return path; - return path.Substring (0, path.Length - 1); - } - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.Version.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.Version.cs deleted file mode 100644 index f18d6b5ad20..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.Version.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Xamarin.Installer.Common -{ - public static partial class Extensions - { - public static Version CloneFillWithZeros (this Version v) - { - return v.CloneValidVersion (); - } - - public static Version CloneValidVersion (this Version v, int defaultMajor = -1, int defaultMinor = -1, int defaultBuild = -1, int defaultRevision = -1) - { - if (v == null) - return null; - - return new Version ( - GetValidValue (v.Major, defaultMajor), - GetValidValue (v.Minor, defaultMinor), - GetValidValue (v.Build, defaultBuild), - GetValidValue (v.Revision, defaultRevision) - ); - } - - static int GetValidValue (int versionPart, int defaultValue) - { - if (versionPart >= 0) - return versionPart; - - return defaultValue > 0 ? defaultValue : 0; - } - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.cs deleted file mode 100644 index d43deb59051..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Extensions.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Xamarin.Web.Installer -{ - public static partial class Extensions - { - static readonly DateTime epoch = new DateTime (1970, 1, 1, 0, 0, 0, 0).ToUniversalTime (); - - public static string JsonQuoted (this string text) - { - return "\"" + text + "\""; - } - - public static long ToUnixTimestamp (this DateTime dt) - { - return (long)(dt - epoch).TotalSeconds; - } - - public static string ToBase64 (this string data) - { - if (String.IsNullOrEmpty (data)) - return String.Empty; - - return Convert.ToBase64String (Encoding.UTF8.GetBytes (data)); - } - - public static string FromBase64 (this string data) - { - if (String.IsNullOrEmpty (data)) - return String.Empty; - - return Encoding.UTF8.GetString (Convert.FromBase64String (data)); - } - - public static IEnumerable DistinctBy - (this IEnumerable source, Func keySelector) - { - HashSet knownKeys = new HashSet (); - foreach (TSource element in source) { - if (knownKeys.Add (keySelector (element))) { - yield return element; - } - } - } - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Helpers.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Helpers.cs deleted file mode 100644 index 14551f9d537..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Helpers.cs +++ /dev/null @@ -1,175 +0,0 @@ -using Microsoft.Win32; -using System; -using System.IO; - - -namespace Xamarin.Installer.Common -{ - public static class Helpers - { - const string INSTALLER_MACHINE_ID_REGISTRY_KVALUE = "IMID"; - static bool onWindows; - public static readonly string UserApplicationDataPath = Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData); - public static readonly string XamarinBaseRegistryKValue = "SOFTWARE\\Xamarin\\MonoAndroid"; - - static Helpers () - { - onWindows = Environment.OSVersion.Platform != PlatformID.MacOSX && Environment.OSVersion.Platform != PlatformID.Unix; - } - - public static Guid GetMachineID () - { - if (onWindows) - return WindowsGetMachineID (); - else - return UnixGetMachineID (); - } - - static Guid UnixGetMachineID () - { - string idPath = Path.Combine (UserApplicationDataPath, "Xamarin", ".machineid"); - Guid machineId; - - try { - if (!File.Exists (idPath)) - return GenerateAndSaveId (idPath); - - string guid = File.ReadAllText (idPath).Trim (); - if (String.IsNullOrEmpty (guid)) - return GenerateAndSaveId (idPath); - else if (!Guid.TryParse (guid, out machineId)) - return GenerateAndSaveId (idPath); - return machineId; - } catch (Exception) { - // ignore - return Guid.NewGuid (); - } - } - - static Guid WindowsGetMachineID () - { - string uuid; - Guid machineId; - if (!GetRegistryKeyValue (XamarinBaseRegistryKValue, INSTALLER_MACHINE_ID_REGISTRY_KVALUE, out uuid, RegistryHive.CurrentUser) || String.IsNullOrEmpty (uuid)) { - machineId = Guid.NewGuid (); - SetRegistryKeyValue (XamarinBaseRegistryKValue, INSTALLER_MACHINE_ID_REGISTRY_KVALUE, machineId.ToString (), RegistryValueKind.String, RegistryHive.CurrentUser); - } else { - if (!Guid.TryParse (uuid, out machineId) || machineId == Guid.Empty) - machineId = Guid.NewGuid (); - } - - return machineId; - } - - static void SaveIdToFile (string idPath, Guid machineId) - { - string xamarinDir = Path.GetDirectoryName (idPath); - if (!Directory.Exists (xamarinDir)) - Directory.CreateDirectory (xamarinDir); - File.WriteAllText (idPath, machineId.ToString ()); - } - - static Guid GenerateAndSaveId (string idPath) - { - var machineId = Guid.NewGuid (); - SaveIdToFile (idPath, machineId); - return machineId; - } - - public static bool GetRegistryKeyValue (string subKeyPath, string keyName, out T result, RegistryHive hive = RegistryHive.LocalMachine, bool check64Node = true) - { - result = default (T); - if (String.IsNullOrEmpty (subKeyPath)) - return false; - - string wow3264Value = null; - if (check64Node && hive == RegistryHive.LocalMachine) { - int offset = 0; - if (subKeyPath [0] == '\\') - offset++; - if (subKeyPath.StartsWith ("SOFTWARE\\", StringComparison.OrdinalIgnoreCase) || subKeyPath.StartsWith ("\\SOFTWARE\\", StringComparison.OrdinalIgnoreCase)) { - offset += 8; - wow3264Value = "SOFTWARE\\Wow6432Node\\" + subKeyPath.Substring (offset + 1); - } - } - - if (!String.IsNullOrEmpty (wow3264Value) && GetRegistryKeyValueInternal(wow3264Value, keyName, out result, hive)) - return true; - return GetRegistryKeyValueInternal(subKeyPath, keyName, out result, hive); - } - - static bool GetRegistryKeyValueInternal (string subKeyPath, string keyName, out T result, RegistryHive hive = RegistryHive.LocalMachine) - { - result = default (T); - RegistryKey parent = HiveToKey (hive); - using (RegistryKey rk = parent.OpenSubKey (subKeyPath, false)) { - if (rk == null) - return false; - - object o = rk.GetValue (keyName); - if (o == null) - return false; - - try { - result = (T)Convert.ChangeType (o, typeof (T)); - return true; - } catch { - // ignore - } - - return false; - } - } - - public static void SetRegistryKeyValue (string subKeyPath, string keyName, object value, RegistryValueKind kind = RegistryValueKind.String, RegistryHive hive = RegistryHive.CurrentUser) - { - if (String.IsNullOrEmpty (subKeyPath)) - throw new ArgumentException ("subKeyPath"); - if (String.IsNullOrEmpty (keyName)) - throw new ArgumentException ("keyName"); - - RegistryKey parent = HiveToKey (hive); - RegistryKey rk = null; - try { - rk = parent.OpenSubKey (subKeyPath, true); - if (rk == null) { - rk = parent.CreateSubKey (subKeyPath); - if (rk == null) - return; - } - - rk.SetValue (keyName, value, kind); - } finally { - if (rk != null) - rk.Dispose (); - } - } - - public static RegistryKey HiveToKey (RegistryHive hive) - { - switch (hive) { - case RegistryHive.ClassesRoot: - return Registry.ClassesRoot; - - case RegistryHive.CurrentConfig: - return Registry.CurrentConfig; - - case RegistryHive.CurrentUser: - return Registry.CurrentUser; - - case RegistryHive.LocalMachine: - return Registry.LocalMachine; - - case RegistryHive.PerformanceData: - return Registry.PerformanceData; - - case RegistryHive.Users: - return Registry.Users; - - default: - throw new InvalidOperationException ("Unknown registry hive"); - } - } - - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/IHelpers.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/IHelpers.cs deleted file mode 100644 index 3e482ec6d42..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/IHelpers.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; - -namespace Xamarin.Installer.Common -{ - /// - /// Interface to be implemented by the client code to help the installer perform certain tasks that - /// may be implemented differently in different environments (e.g. Unified Installer vs IDE vs MSBuild - /// targets in Xamarin.Android) - /// - public interface IHelpers - { - /// - /// Returns true if the app is running on ARM64 machine - /// - bool IsArm64 { get; } - - /// - /// Returns true if the current OS is a 64-bit one - /// - bool Is64BitOS { get; } - - /// - /// Gets the home directory of the current user. - /// - /// Home directory of the current user - string HomeDirectory { get; } - - /// - /// Gets the name of the current user. - /// - /// The name of the current user. - string UserName { get; } - - /// - /// Gets a value indicating the current OS has case-sensitive (or case-aware) file systems - /// - /// true if the current OS has case sensitive file systems; otherwise, false. - bool IsCaseSensitiveFileSystem { get; } - - /// - /// Determine whether the file at exists and is a special file - /// (e.g. a paging file on Windows or a character device on Unix) - /// - /// Path to the file - /// true if file is a special one, false otherwise - bool IsSpecialFile (string filePath); - - /// - /// Copy a special file (such as Windows paging file or Unix character device) from - /// to - /// - /// Source file - /// Destination file - void CopySpecialFile (string source, string target); - - /// - /// Attempt to determine the content length of the resource at the URL. - /// - /// URL to obtain content length of - /// The resource's content length. 0 should be returned if an error accessing the URL occurs. - ulong GetUrlContentLength (Uri url); - - /// - /// Unzip the archive found at the path pointed to by placing its contents in the - /// directory indicated by . If is specified, the - /// extracted files will be owned by that user. - /// - /// The archive is will contain a single top-level directory which should be located by - /// the unzipper and used, in combination with , as the return value of this method. - /// Top-level directory in which to unpack the archive - /// Path to the compressed archive - /// Owner of the unpacked content - /// Path to the root directory of the *unpacked* content - string Unzip (string baseDirectory, string archivePath, string fileOwnerName = null); - - /// - /// Unzip the archive found at the path pointed to by placing its contents in the - /// directory indicated by . If is specified, the - /// extracted files will be owned by that user. - /// - /// The archive is will contain a single top-level directory which should be located by - /// the unzipper and used, in combination with , as the return value of this method. - /// Top-level directory in which to unpack the archive - /// Path to the compressed archive - /// Owner of the unpacked content - /// - /// Path to the root directory of the *unpacked* content - string Unzip (string baseDirectory, string archivePath, string fileOwnerName = null, InstallationProgressEventArgs.InstallationProgressActionDelegate progressCallback = null); - - /// - /// Download contents of the given and place it in the string - /// - /// true, if download was successful, false otherwise. - /// URL to download from - /// Output string - bool DownloadToString (Uri url, out string output); - - /// - /// Checks whether web resource pointed to by exists. - /// - /// true, if URL exists, false otherwise. - /// URL to check the existence of - bool URLExists (Uri url); - - /// - /// Gets the registry key value. On platforms other than Windows it should return an empty string. - /// - /// The registry key value or empty string on platforms other than Windows. - /// Sub key path. - /// Key name. - /// If set to true check the 32-bit registry hive on 64-bit windows. - string GetRegistryKeyValue (string subKeyPath, string keyName, bool check64Node); - - /// - /// Look up translation of the provided string. - /// - /// Translated string - /// String to look up translation of - string GetString (string s); - - /// - /// Look up translation of the provided string, for strings which include numerals. - /// - /// Translated string - /// String to look up translation of, singular form - /// String to look up translation of, plural form - /// integer used to select plural or singular form of the string - string GetPluralString (string s, string p, int n); - - /// - /// Gets existing property value by its key - /// - /// Property key - /// Default value - /// Property value or defaultValue - string GetProperty (string key, string defaultValue = ""); - - /// - /// Sets a new property or updates an existing one - /// - /// Property key - /// Property value - void SetProperty (string key, string value); - - Task CheckIfNetworkIsAvailableAsync (); - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/ILogAdapter.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/ILogAdapter.cs deleted file mode 100644 index 6b555555877..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/ILogAdapter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Xamarin.Installer.Common -{ - public interface ILogAdapter - { - void Action(string format, params object[] parms); - void Debug (string format, params object[] parms); - void Debug (string format, Exception ex, params object[] parms); - void Error (string format, params object[] parms); - void Exception (string format, Exception ex, params object[] parms); - void Info (string format, params object[] parms); - void Warning (string format, params object[] parms); - void SetOperationStatus (OperationStatus status); - } - - public interface ILogAdapterExtended: ILogAdapter - { - void SaveManifest (string manifestName, string content); - } - - public interface ILogPathProvider - { - string GetLogPath(string fileNameSuffix); - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/InstallationProgressEventArgs.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/InstallationProgressEventArgs.cs deleted file mode 100644 index b5c1c6871ca..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/InstallationProgressEventArgs.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; - -namespace Xamarin.Installer.Common -{ - /// - /// Passed as the argument to the the AndroidSDKInstaller.InstallationProgress event - /// handler. - /// - public class InstallationProgressEventArgs : EventArgs - { - /// - /// Installation progress message - /// - public string Message { get; set; } - - /// - /// Progress is in range 0f .. 100f - /// - public float Progress { get; set; } - - /// - /// This is True for the very start of a component installation - /// - public bool IsInitialEvent { get; set; } - - /// - /// Definition for progress callback - /// - /// - public delegate void InstallationProgressActionDelegate (float progress); - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Log.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Log.cs deleted file mode 100644 index 4cdef62027d..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/Log.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.IO; -using System.Text; -using System.Threading; - -namespace Xamarin.Installer.Common -{ - public static class Logger - { - public static ILogAdapter LogAdapter { get; set; } - - public static void Action(string format, params object[] parms) - { - if (LogAdapter == null) - return; - LogAdapter.Action(format, parms); - } - - public static void Debug (string format, params object[] parms) - { - if (LogAdapter == null) - return; - LogAdapter.Debug (format, parms); - } - - public static void Debug (string format, Exception ex, params object[] parms) - { - if (LogAdapter == null) - return; - LogAdapter.Debug (format, ex, parms); - } - - public static void Error (string format, params object[] parms) - { - if (LogAdapter == null) - return; - LogAdapter.Error (format, parms); - } - - public static void Exception (string format, Exception ex, params object[] parms) - { - if (LogAdapter == null) - return; - LogAdapter.Exception (format, ex, parms); - } - - public static void Info (string format, params object[] parms) - { - if (LogAdapter == null) - return; - LogAdapter.Info (format, parms); - } - - public static void Warning (string format, params object[] parms) - { - if (LogAdapter == null) - return; - LogAdapter.Warning (format, parms); - } - - public static void SetOperationStatus (OperationStatus status) - { - if (LogAdapter == null) - return; - LogAdapter.SetOperationStatus (status); - } - - public static void LogManifest (string manifestName, Stream contentStream) - { - contentStream.Seek (0, SeekOrigin.Begin); - var content = new StreamReader (contentStream).ReadToEnd (); - if (LogAdapter is ILogAdapterExtended extendedLogAdapter) { - extendedLogAdapter.SaveManifest (manifestName, content); - } else { - Debug ($"{manifestName} :\n{content}"); - } - } - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/OperationStatus.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/OperationStatus.cs deleted file mode 100644 index 70ba8d3a370..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/OperationStatus.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Xamarin.Installer.Common -{ - public enum OperationStatus - { - Failure - } -} diff --git a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/XmlElementExtensions.cs b/src/Xamarin.Installer.Common/Xamarin.Installer.Common/XmlElementExtensions.cs deleted file mode 100644 index 3cb0c502de9..00000000000 --- a/src/Xamarin.Installer.Common/Xamarin.Installer.Common/XmlElementExtensions.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; - -namespace Xamarin.Installer.Common -{ - public static class XmlElementExtensions - { - public static string SelectSingleElementValue (this XmlElement element, string xpath) - { - if (element == null || String.IsNullOrEmpty (xpath)) - return null; - - var found = element.SelectSingleNode (xpath) as XmlElement; - return found == null ? null : found.InnerText; - } - - public static string GetChildValue (this XmlElement element, string childName) - { - if (element == null || String.IsNullOrEmpty (childName)) - return null; - - XmlElement child = element[childName]; - if (child == null) - return null; - - string ret = child.InnerText; - if (String.IsNullOrEmpty (ret)) - return null; - - return ret; - } - - public static bool GetAttributeValue (this XmlElement element, string attributeName, out T result) - { - result = default (T); - if (element == null) - return false; - return ConvertValue (element.GetAttribute (attributeName), out result); - } - - public static bool GetChildValue (this XmlElement element, string childName, out T result) - { - result = default (T); - if (element == null) - return false; - return ConvertValue (element.GetChildValue (childName), out result); - } - - static bool ConvertValue (string value, out T result) - { - result = default (T); - if (value != null) - value = value.Trim (); - if (String.IsNullOrEmpty (value)) - return false; - - if (typeof (T) == typeof (string)) { - result = (T) ((object) value); - return true; - } - - try { - result = (T) Convert.ChangeType (value, typeof (T)); - } catch { - // ignore - return false; - } - - return true; - } - - public static XmlElement GetChildElement (this XmlElement parent, XmlNamespaceManager nsmgr, string xpath, bool required = true) - { - var ret = parent.SelectSingleNode (xpath, nsmgr) as XmlElement; - if (ret == null && required) - throw new InvalidOperationException ("Required child element not found"); - return ret; - } - } -} diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidPropertiesTests.cs b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidPropertiesTests.cs deleted file mode 100644 index 477f1e5dd4f..00000000000 --- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidPropertiesTests.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using NUnit.Framework; -using Xamarin.Installer.AndroidSDK; - -namespace Xamarin.Android.Tools.Tests; - -[TestFixture] -public class AndroidPropertiesTests -{ - [TestCase ("key=value", "key", "value")] - [TestCase (" \t\fkey \t\f= \t\fvalue", "key", "value")] - [TestCase ("key:value", "key", "value")] - [TestCase ("key \t\f: \t\fvalue", "key", "value")] - [TestCase ("key value", "key", "value")] - [TestCase ("key", "key", "")] - [TestCase ("key \t\f", "key", "")] - [TestCase ("key=", "key", "")] - [TestCase ("key:", "key", "")] - [TestCase ("=value", "", "value")] - [TestCase (":value", "", "value")] - [TestCase ("=", "", "")] - [TestCase ("key==value", "key", "=value")] - [TestCase ("key=:value", "key", ":value")] - [TestCase ("key=value \t\f", "key", "value \t\f")] - [TestCase ("key=#value!:=end", "key", "#value!:=end")] - [TestCase ("key=\"value\"", "key", "\"value\"")] - [TestCase ("key='value'", "key", "'value'")] - [TestCase ("\\#key=value", "#key", "value")] - [TestCase ("\\!key=value", "!key", "value")] - [TestCase ("a\\ b\\:c\\=d=value", "a b:c=d", "value")] - [TestCase ("key=\\ value", "key", " value")] - [TestCase ("key=\\t\\r\\n\\f\\\\", "key", "\t\r\n\f\\")] - [TestCase ("\\t\\r\\n\\f\\\\=value", "\t\r\n\f\\", "value")] - [TestCase ("key=\\b\\z\\0", "key", "bz0")] - [TestCase ("\\u006bey=\\u00e9\\u4E2D", "key", "\u00e9\u4e2d")] - [TestCase ("key=\\uD83D\\uDE00", "key", "\ud83d\ude00")] - [TestCase ("key=\\u000g\\u000Z", "key", "\u0010\u0023")] - [TestCase ("key=\\uu000", "key", "\ue000")] - [TestCase ("key=first\\\n \t\fsecond", "key", "firstsecond")] - [TestCase ("key=first\\\r \t\fsecond", "key", "firstsecond")] - [TestCase ("key=first\\\r\n \t\fsecond", "key", "firstsecond")] - [TestCase ("ke\\\n \t\fy=value", "key", "value")] - [TestCase ("\\\n \t\fkey=value", "key", "value")] - [TestCase ("key=\\\n \t\fvalue", "key", "value")] - [TestCase ("key=\\\n#value", "key", "#value")] - [TestCase ("key=\\\n!value", "key", "!value")] - [TestCase ("key=\\\\\n", "key", "\\")] - [TestCase ("key=\\\\\\\nvalue", "key", "\\value")] - [TestCase ("key=first\\\n \t\f\n", "key", "first")] - [TestCase ("key=first\\\n", "key", "first")] - [TestCase ("key=first\\", "key", "first\uffff")] - [TestCase ("key\\", "key\uffff", "")] - [TestCase ("\\", "\uffff", "")] - [TestCase ("\\\n", "", "")] - [TestCase ("key=\\\n", "key", "")] - [TestCase ("\u00e9=\u00ff", "\u00e9", "\u00ff")] - [TestCase ("\u00ef\u00bb\u00bfkey=value", "\u00ef\u00bb\u00bfkey", "value")] - [TestCase ("a\0b=c\0d", "a\0b", "c\0d")] - public void ReadProperty (string contents, string key, string value) - { - var properties = ReadProperties (contents); - Assert.AreEqual (1, properties.Count); - Assert.AreEqual (value, properties [key]); - } - - [TestCase (1019, "\\u00e9", "\u00e9")] - [TestCase (1020, "\\u00e9", "\u00e9")] - [TestCase (1021, "\\u00e9", "\u00e9")] - [TestCase (1022, "\\u00e9", "\u00e9")] - [TestCase (1023, "\\u00e9", "\u00e9")] - [TestCase (1024, "\\u00e9", "\u00e9")] - [TestCase (1022, "\\\r\n \t\f", "")] - [TestCase (1023, "\\\r\n \t\f", "")] - [TestCase (1024, "\\\r\n \t\f", "")] - public void ReadPropertyAcrossReaderBufferBoundary (int escapeOffset, string escape, string decodedEscape) - { - // Latin-1 uses one byte per character; StreamReader's default byte buffer is 1024 bytes. - const string key = "key="; - string prefix = new string ('x', escapeOffset - key.Length); - var properties = ReadProperties (key + prefix + escape + "tail\nother=value"); - Assert.AreEqual (2, properties.Count); - Assert.AreEqual (prefix + decodedEscape + "tail", properties ["key"]); - Assert.AreEqual ("value", properties ["other"]); - } - - [TestCase ("\n")] - [TestCase ("\r")] - [TestCase ("\r\n")] - public void ReadMultipleProperties (string newline) - { - string contents = string.Join (newline, [ - "", - " \t\f# comment\\", - " \t\f! comment", - " \t\f", - "key=first", - "KEY=uppercase", - "key=last", - "other=value", - ]); - var properties = ReadProperties (contents); - Assert.AreEqual (3, properties.Count); - Assert.AreEqual ("last", properties ["key"]); - Assert.AreEqual ("uppercase", properties ["KEY"]); - Assert.AreEqual ("value", properties ["other"]); - } - - [TestCase ("")] - [TestCase (" \t\f\r\n")] - [TestCase ("# comment\\")] - [TestCase ("! comment")] - public void ReadEmptyProperties (string contents) - { - Assert.IsEmpty (ReadProperties (contents)); - } - - [TestCase ("key=\\u")] - [TestCase ("key=\\u123")] - [TestCase ("key=\\u00-0")] - [TestCase ("\\u12\n3=value")] - public void ReadInvalidUnicodeEscape (string contents) - { - var exception = Assert.Throws (() => ReadProperties (contents)); - Assert.IsNotNull (exception); - Assert.IsInstanceOf (exception.InnerException); - Assert.AreEqual ("Invalid Unicode character.", exception.InnerException?.Message); - } - - [Test] - public void ReadMissingProperties () - { - Assert.IsEmpty (AndroidUtilities.ReadAndroidProperties (null)); - Assert.IsEmpty (AndroidUtilities.ReadAndroidProperties ("")); - Assert.IsEmpty (AndroidUtilities.ReadAndroidProperties (Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ("N")))); - } - - static Dictionary ReadProperties (string contents) - { - string path = Path.Combine (Path.GetTempPath (), "android-properties-" + Guid.NewGuid ().ToString ("N")); - try { - File.WriteAllText (path, contents, Encoding.GetEncoding (28591)); - return AndroidUtilities.ReadAndroidProperties (path); - } finally { - File.Delete (path); - } - } -} diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInstallerTests.cs b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInstallerTests.cs deleted file mode 100644 index 81bd11e289c..00000000000 --- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInstallerTests.cs +++ /dev/null @@ -1,310 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Xml.Linq; -using NUnit.Framework; -using Xamarin.Installer.AndroidSDK; -using Xamarin.Installer.AndroidSDK.Common; -using Xamarin.Installer.AndroidSDK.GoogleV2; -using Xamarin.Installer.AndroidSDK.Manager; -using Xamarin.Installer.Common; - -namespace Xamarin.Android.Tools.Tests; - -[TestFixture] -[NonParallelizable] -public class AndroidSdkInstallerTests -{ - [Test] - [System.Diagnostics.CodeAnalysis.SuppressMessage ("Security", "CA5350", Justification = "Tests SHA-1 checksums supported by Android SDK manifests.")] - public void InstallValidatesAllArchivesBeforeExtraction ( - [Values (true, false)] bool throwIfInvalidComponentsFound, - [Values (-1, 0, 1)] int invalidArchiveIndex, - [Values ("sha1", "sha256")] string checksumType, - [Values (false, true)] bool ignoreChecksumErrors) - { - var root = Path.Combine (Path.GetTempPath (), "android-sdk-installer-" + Guid.NewGuid ().ToString ("N")); - var sdkPath = Path.Combine (root, "android-sdk"); - var manifestPath = Path.Combine (root, "manifest.xml"); - var log = new InstallerLogAdapter (); - var previousLogAdapter = Logger.LogAdapter; - Directory.CreateDirectory (root); - try { - Logger.LogAdapter = log; - var manifest = new XElement ("android", - new XAttribute (XNamespace.Xmlns + "sdk", "http://schemas.android.com/sdk/android/repo/repository2/03"), - new XAttribute (XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance")); - for (int i = 0; i < 2; i++) { - var name = "component-" + i; - var archivePath = Path.Combine (root, name + ".zip"); - using (var zip = ZipFile.Open (archivePath, ZipArchiveMode.Create)) - using (var writer = new StreamWriter (zip.CreateEntry ("payload/installed.txt").Open ())) - writer.Write (name); - - using var hash = checksumType == "sha1" ? (HashAlgorithm) SHA1.Create () : SHA256.Create (); - using var stream = File.OpenRead (archivePath); - var checksum = Convert.ToHexString (hash.ComputeHash (stream)); - if (i == invalidArchiveIndex) - checksum = new string ('0', checksum.Length); - - manifest.Add (new XElement ("platform-tools", - new XAttribute ("original-type", "generic"), - new XAttribute ("revision", "1.0.0"), - new XAttribute ("path", name), - new XAttribute ("filesystem-path", name), - new XAttribute ("description", name), - new XAttribute ("license", "test-license"), - new XAttribute ("manifest-url", new Uri (manifestPath).AbsoluteUri), - new XElement ("urls", new XElement ("url", - new XAttribute ("size", stream.Length), - new XAttribute ("checksum", checksum), - new XAttribute ("checksum-type", checksumType), - new XAttribute ("host-os", AndroidUtilities.GetPlatformOS ()), - new XAttribute ("host-bits", Environment.Is64BitOperatingSystem ? 64 : 32), - new Uri (archivePath).AbsoluteUri)))); - } - manifest.Save (manifestPath); - var installer = new AndroidSDKInstaller (new Helper (manifestFilePath: manifestPath), manifestURL: new Uri (manifestPath)); - Assert.IsFalse (installer.IgnoreArchiveChecksumErrors); - installer.IgnoreArchiveChecksumErrors = ignoreChecksumErrors; - installer.Repository.Parse (); - var components = installer.Repository.Components; - Assert.AreEqual (2, components.Count); - for (int i = 0; i < components.Count; i++) { - var archive = components [i].Archives.Single (); - archive.DownloadedFilePath = archive.Url.LocalPath; - Assert.IsTrue (archive.IsInstallable (verifyChecksum: false)); - Assert.AreEqual (i != invalidArchiveIndex, archive.IsInstallable ()); - } - int installationProgressCount = 0; - installer.InstallationProgress += (sender, args) => installationProgressCount++; - Assert.IsTrue (installer.Discover (new List { sdkPath }, fromScratch: false)); - var instance = installer.FindInstance (sdkPath); - Assert.IsNotNull (instance); - - bool rejectArchives = invalidArchiveIndex >= 0 && !ignoreChecksumErrors; - if (rejectArchives && throwIfInvalidComponentsFound) { - Assert.Throws (() => - installer.Install (instance, components, throwIfInvalidComponentsFound)); - } else { - Assert.DoesNotThrow (() => installer.Install (instance, components, throwIfInvalidComponentsFound)); - } - - if (rejectArchives) { - Assert.AreEqual (0, installationProgressCount, "Installation must not start for any component."); - Assert.IsFalse (Directory.Exists (sdkPath), "No component must be extracted."); - Assert.Greater (log.Errors, 0, "A rejected installation must report an error."); - } else { - Assert.Greater (installationProgressCount, 0); - for (int i = 0; i < components.Count; i++) { - var componentPath = Path.Combine (sdkPath, "component-" + i); - Assert.AreEqual ("component-" + i, File.ReadAllText (Path.Combine (componentPath, "installed.txt"))); - Assert.IsTrue (File.Exists (Path.Combine (componentPath, "package.xml"))); - } - Assert.AreEqual (0, log.Errors); - Assert.AreEqual (invalidArchiveIndex >= 0 ? 1 : 0, log.Actions); - } - } finally { - Logger.LogAdapter = previousLogAdapter; - Directory.Delete (root, recursive: true); - } - } - - [TestCase (true)] - [TestCase (false)] - public void ChecksumOverrideDoesNotIgnoreInvalidHost (bool throwIfInvalidComponentsFound) - { - var root = Path.Combine (Path.GetTempPath (), "android-sdk-installer-" + Guid.NewGuid ().ToString ("N")); - Directory.CreateDirectory (root); - try { - var archivePath = Path.Combine (root, "archive.zip"); - using (ZipFile.Open (archivePath, ZipArchiveMode.Create)) {} - var archive = new Archive (AndroidUtilities.GetPlatformOS ()) { - DownloadedFilePath = archivePath, - ChecksumType = "sha256", - Checksum = Convert.ToHexString (SHA256.HashData (File.ReadAllBytes (archivePath))), - }; - var installer = new AndroidSDKInstaller (new Helper (), AndroidManifestType.Local) { - IgnoreArchiveChecksumErrors = true, - }; - var component = new RemotePackage (installer.Repository, new Uri (archivePath), null, installer, [archive]) { - Path = "test-component", - FileSystemPath = "test-component", - }; - component.Verify (); - Assert.IsTrue (archive.IsInstallable ()); - archive.HostArch = "unsupported-test-host"; - Assert.IsFalse (archive.IsInstallable (verifyChecksum: false)); - var sdkPath = Path.Combine (root, "android-sdk"); - Assert.IsTrue (installer.Discover ([sdkPath])); - var instance = installer.FindInstance (sdkPath); - Assert.IsNotNull (instance); - if (throwIfInvalidComponentsFound) - Assert.Throws (() => installer.Install (instance, [component])); - else - Assert.DoesNotThrow (() => installer.Install (instance, [component], throwIfInvalidComponentsFound: false)); - Assert.IsFalse (Directory.Exists (sdkPath)); - } finally { - Directory.Delete (root, recursive: true); - } - } - - sealed class InstallerLogAdapter : ILogAdapter - { - public int Errors { get; private set; } - public int Actions { get; private set; } - - public void Error (string format, params object[] parms) => Errors++; - public void Warning (string format, params object[] parms) {} - public void Exception (string format, Exception ex, params object[] parms) => Errors++; - public void Action (string format, params object[] parms) => Actions++; - public void Debug (string format, params object[] parms) {} - public void Debug (string format, Exception ex, params object[] parms) {} - public void Info (string format, params object[] parms) {} - public void SetOperationStatus (OperationStatus status) {} - } - - [Test] - public void DiscoverSdkFromSourceProperties () - { - var root = Path.Combine (Path.GetTempPath (), "android-sdk-installer-" + Guid.NewGuid ().ToString ("N")); - var platformPath = Path.Combine (root, "platforms", "android-35"); - Directory.CreateDirectory (platformPath); - try { - var propertiesPath = Path.Combine (platformPath, "source.properties"); - File.WriteAllText (propertiesPath, """ - Pkg.Revision = 35.0.1 - Pkg.Desc = Android SDK \ - Platform \u0033\u0035 - Platform.Version = 15 - AndroidVersion.ApiLevel = 35 - Layoutlib.Api = 15 - """); - var installer = new AndroidSDKInstaller (new Helper (), AndroidManifestType.Local); - Assert.IsTrue (installer.Discover (new List { root })); - var instance = installer.FindInstance (root); - Assert.IsNotNull (instance); - var component = instance.Components.Single (c => c.ManifestURL == new Uri (propertiesPath)); - Assert.AreEqual ("Android SDK Platform 35", component.DisplayName); - Assert.AreEqual (new AndroidRevision ("35.0.1"), component.InstalledRevision); - } finally { - Directory.Delete (root, recursive: true); - } - } - - // Verbatim from https://dl.google.com/android/repository/google_apis-24_r1.zip - const string GoogleApis24Manifest = """ - # SDK Add-on Manifest - - name=Google APIs - name-id=google_apis - vendor=Google Inc. - vendor-id=google - description=Android + Google APIs - - # version of the Android platform on which this add-on is built. - api=24 - - # revision of the add-on - revision=1 - - # list of libraries, separated by a semi-colon. - libraries=com.google.android.maps;com.android.future.usb.accessory;com.google.android.media.effects - - # details for each library - com.google.android.maps=maps.jar;API for Google Maps - com.android.future.usb.accessory=usb.jar;API for USB Accessories - com.google.android.media.effects=effects.jar;Collection of video effects - - SystemImage.GpuSupport=true - """; - - [TestCase ("UTF-8", false)] - [TestCase ("UTF-8", true)] - [TestCase ("UTF-16LE", true)] - [TestCase ("UTF-16BE", true)] - public void DiscoverAddonLibrariesFromManifestIni (string manifestEncoding, bool writePreamble) - { - var root = Path.Combine (Path.GetTempPath (), "android-sdk-installer-" + Guid.NewGuid ().ToString ("N")); - var addonPath = Path.Combine (root, "add-ons", "addon-google_apis-google-24"); - Directory.CreateDirectory (addonPath); - try { - var propertiesPath = Path.Combine (addonPath, "source.properties"); - File.WriteAllText (propertiesPath, """ - Addon.NameDisplay=Google APIs - Addon.NameId=google_apis - Addon.VendorDisplay=Google Inc. - Addon.VendorId=google - AndroidVersion.ApiLevel=24 - Pkg.Desc=Android + Google APIs - Pkg.Revision=1 - """); - Encoding encoding = manifestEncoding switch { - "UTF-8" => new UTF8Encoding (writePreamble), - "UTF-16LE" => new UnicodeEncoding (bigEndian: false, byteOrderMark: writePreamble), - "UTF-16BE" => new UnicodeEncoding (bigEndian: true, byteOrderMark: writePreamble), - _ => throw new ArgumentOutOfRangeException (nameof (manifestEncoding), manifestEncoding, null), - }; - var manifest = writePreamble - ? "libraries=maps\nmaps=maps.jar;M\u00fcnchen Maps\n" - : GoogleApis24Manifest; - File.WriteAllText (Path.Combine (addonPath, "manifest.ini"), manifest.Replace ("\r\n", "\n").Replace ("\n", "\r\n"), encoding); - var installer = new AndroidSDKInstaller (new Helper (), AndroidManifestType.Local); - Assert.IsTrue (installer.Discover (new List { root })); - var instance = installer.FindInstance (root); - Assert.IsNotNull (instance); - var component = instance.Components.Single (c => c.ManifestURL == new Uri (propertiesPath)); - var info = component.Info as AndroidComponentInfoAddon; - Assert.IsNotNull (info); - var libraries = info.Libraries; - Assert.IsNotNull (libraries); - var expected = writePreamble - ? new [] { "maps|maps.jar|M\u00fcnchen Maps" } - : new [] { - "com.google.android.maps|maps.jar|API for Google Maps", - "com.android.future.usb.accessory|usb.jar|API for USB Accessories", - "com.google.android.media.effects|effects.jar|Collection of video effects", - }; - CollectionAssert.AreEqual (expected, libraries.Select (l => $"{l.Name}|{l.LocalJarPath}|{l.Description}")); - } finally { - Directory.Delete (root, recursive: true); - } - } - - [TestCase ("JAVA_VERSION=\"21.0.3\"")] - [TestCase ("JAVA_VERSION='21.0.3'")] - [TestCase ("JAVA_VERSION=21.0.3")] - [TestCase ("JAVA_VERSION=\\\"21.0.\\u0033\\\"")] - public void DiscoverJdkRevisionFromReleaseProperties (string contents) - { - var root = Path.Combine (Path.GetTempPath (), "android-jdk-installer-" + Guid.NewGuid ().ToString ("N")); - Directory.CreateDirectory (root); - try { - File.WriteAllText (Path.Combine (root, "release"), contents); - var installer = new JavaDependencyInstaller (new Helper ()) { JdkPath = root }; - Assert.IsTrue (installer.GetJdkRevision (out var revision)); - Assert.AreEqual (new AndroidRevision ("21.0.3"), revision); - } finally { - Directory.Delete (root, recursive: true); - } - } - - [Test] - public void DiscoverMissingSdkForFirstTimeInstallation () - { - var root = Path.Combine (Path.GetTempPath (), "android-sdk-installer-" + Guid.NewGuid ().ToString ("N")); - var sdkPath = Path.Combine (root, "android-sdk"); - Directory.CreateDirectory (root); - try { - var installer = new AndroidSDKInstaller (new Helper (), AndroidManifestType.Local); - Assert.IsTrue (installer.Discover (new List { sdkPath })); - Assert.AreEqual (sdkPath, installer.FindInstance (sdkPath)?.Path); - } finally { - Directory.Delete (root, recursive: true); - } - } -} diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj index 08fe43f8e5a..f25a3baf483 100644 --- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj +++ b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj @@ -21,7 +21,6 @@ - @@ -32,7 +31,6 @@ - diff --git a/src/Xamarin.Installer.AndroidSDK/Feeds/AndroidManifestFeed_d18.0.xml b/tools/workload-dependencies/AndroidManifestFeed_d18.0.xml similarity index 100% rename from src/Xamarin.Installer.AndroidSDK/Feeds/AndroidManifestFeed_d18.0.xml rename to tools/workload-dependencies/AndroidManifestFeed_d18.0.xml diff --git a/tools/workload-dependencies/WorkloadDependencies.proj b/tools/workload-dependencies/WorkloadDependencies.proj index e0553374c97..cc02249e26b 100644 --- a/tools/workload-dependencies/WorkloadDependencies.proj +++ b/tools/workload-dependencies/WorkloadDependencies.proj @@ -43,7 +43,7 @@ DependsOnTargets="_CheckDeps"> - <_AndroidManifestFeed>$(MSBuildThisFileDirectory)..\..\src\Xamarin.Installer.AndroidSDK\Feeds\AndroidManifestFeed_d18.0.xml + <_AndroidManifestFeed>$(MSBuildThisFileDirectory)AndroidManifestFeed_d18.0.xml <_Feed Condition=" Exists('$(_AndroidManifestFeed)') ">$(_AndroidManifestFeed) <_Feed Condition=" '$(_Feed)' == '' ">https://aka.ms/AndroidManifestFeed/d18-0 <_Project>$(MSBuildThisFileDirectory)workload-dependencies.csproj