From 467f42de3c73e7f8a12ac4d7bd3d5113a1c76a74 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 23 Aug 2017 10:27:35 -0500 Subject: [PATCH] [android-toolchain] Windows build support (#743) * Bump LibZipSharp for Windows fixes Problems fixed on Windows: - Many `RequiredPrograms` are n/a on Windows - Setup `AndroidSdkItem` for Windows downloads - `AcceptAndroidSdkLicenses` should run `.bat` file on Windows - `UnzipDirectoryChildren` was running `/bin/mv` and hitting `PathTooLongException` while using `ZipFile.ExtractToDirectory` - references to `libzip.mdproj` are conditional on Windows, will be getting `libzip` from NuGet in the future UnzipDirectoryChildren: - on Windows we are using `System.IO.Compression` to extract directly into the destination and avoid `%TEMP%` to workaround `MAX_PATH` - Other platforms continue to use `unzip`, in order to preserve file attributes General changes: - gitignore for VS 2017 --- .gitignore | 1 + .../android-toolchain.projitems | 19 +++++ build-tools/bundle/bundle.mdproj | 2 +- .../dependencies/dependencies.projitems | 13 ++-- build-tools/libzip/libzip.projitems | 2 +- .../AcceptAndroidSdkLicenses.cs | 4 +- external/LibZipSharp | 2 +- ...amarin.Android.Tools.BootstrapTasks.csproj | 2 +- .../UnzipDirectoryChildren.cs | 70 ++++++++++++------- 9 files changed, 79 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 298afa64bae..83e991d1d50 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ packages .nuget TestResult.xml TestResult-*.xml +.vs/ diff --git a/build-tools/android-toolchain/android-toolchain.projitems b/build-tools/android-toolchain/android-toolchain.projitems index 4c4c3dc7a46..739d9d69c2b 100644 --- a/build-tools/android-toolchain/android-toolchain.projitems +++ b/build-tools/android-toolchain/android-toolchain.projitems @@ -46,6 +46,25 @@ Darwin emulator + + Windows + + + Windows + build-tools\$(XABuildToolsFolder) + + + Windows + platform-tools + + + Windows + tools + + + Windows + emulator + platforms\android-10 diff --git a/build-tools/bundle/bundle.mdproj b/build-tools/bundle/bundle.mdproj index b6e359cfce1..6b495245783 100644 --- a/build-tools/bundle/bundle.mdproj +++ b/build-tools/bundle/bundle.mdproj @@ -37,7 +37,7 @@ mono-runtimes False - + {900A0F71-BAAD-417A-8D1A-8D330297CDD0} libzip False diff --git a/build-tools/dependencies/dependencies.projitems b/build-tools/dependencies/dependencies.projitems index 86f97e3fc94..b59fb788231 100644 --- a/build-tools/dependencies/dependencies.projitems +++ b/build-tools/dependencies/dependencies.projitems @@ -5,15 +5,15 @@ <_AptGetInstall>apt-get -f -u install - - + + p7zip - + autoconf - + automake @@ -36,10 +36,11 @@ 1.8 - $(MSBuildThisFileDirectory)..\scripts\javac-version + $(MSBuildThisFileDirectory)..\scripts\javac-version + javac -version 2>&1 $(_AptGetInstall) openjdk-8-jdk - + pkg-config diff --git a/build-tools/libzip/libzip.projitems b/build-tools/libzip/libzip.projitems index e74166be1f0..7582776ebd8 100644 --- a/build-tools/libzip/libzip.projitems +++ b/build-tools/libzip/libzip.projitems @@ -16,6 +16,6 @@ - + diff --git a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/AcceptAndroidSdkLicenses.cs b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/AcceptAndroidSdkLicenses.cs index 60a0526eb3b..a07923579e1 100644 --- a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/AcceptAndroidSdkLicenses.cs +++ b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/AcceptAndroidSdkLicenses.cs @@ -16,7 +16,9 @@ public override bool Execute () var licdir = Path.Combine (Path.Combine (AndroidSdkDirectory, "licenses")); Directory.CreateDirectory (licdir); - var psi = new ProcessStartInfo (Path.Combine (AndroidSdkDirectory, "tools", "bin", "sdkmanager"), "--licenses") { UseShellExecute = false, RedirectStandardInput = true }; + string _; + var path = Which.GetProgramLocation ("sdkmanager", out _, new [] { Path.Combine (AndroidSdkDirectory, "tools", "bin") }); + var psi = new ProcessStartInfo (path, "--licenses") { UseShellExecute = false, RedirectStandardInput = true }; var proc = Process.Start (psi); for (int i = 0; i < 10; i++) proc.StandardInput.WriteLine ('y'); diff --git a/external/LibZipSharp b/external/LibZipSharp index 1b217dabdef..21995c51103 160000 --- a/external/LibZipSharp +++ b/external/LibZipSharp @@ -1 +1 @@ -Subproject commit 1b217dabdefd5cefa0fdd391498f8cc0462575d6 +Subproject commit 21995c51103c1f59beb0fc21f996889de2d22d87 diff --git a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks.csproj b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks.csproj index f3e5c087282..0568211c629 100644 --- a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks.csproj +++ b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks.csproj @@ -57,7 +57,7 @@ {E248B2CA-303B-4645-ADDC-9D4459D550FD} libZipSharp - + {900A0F71-BAAD-417A-8D1A-8D330297CDD0} libzip False diff --git a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/UnzipDirectoryChildren.cs b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/UnzipDirectoryChildren.cs index 2f50be00025..faeb55eee32 100644 --- a/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/UnzipDirectoryChildren.cs +++ b/src/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/UnzipDirectoryChildren.cs @@ -84,16 +84,35 @@ public override bool Execute () #pragma warning disable 1998 async TTask ExtractFile (string tempDir, string sourceFile, string relativeDestDir, string destinationFolder, Encoding encoding) { - var tempName = Path.GetRandomFileName (); - var nestedTemp = Path.Combine (tempDir, tempName); - Directory.CreateDirectory (nestedTemp); - relativeDestDir = relativeDestDir?.Replace ('\\', Path.DirectorySeparatorChar); if (string.Equals (HostOS, "Windows", StringComparison.OrdinalIgnoreCase)) { - ZipFile.ExtractToDirectory (sourceFile, nestedTemp, encoding); - } - else { + //NOTE: to avoid MAX_PATH, we are not using %TEMP% on Windows + using (var source = File.OpenRead (sourceFile)) + using (var zip = new ZipArchive (source)) { + foreach (var entry in zip.Entries) { + //Directory entries have empty names + if (!string.IsNullOrEmpty (entry.Name)) { + //entry.FullName can have / or \ depending on your .NET version + var entryPath = entry.FullName.Replace ('/', Path.DirectorySeparatorChar); + if (!NoSubdirectory) { + entryPath = entryPath.Substring (entryPath.IndexOf (Path.DirectorySeparatorChar) + 1); + } + var destinationPath = Path.Combine (destinationFolder, relativeDestDir, entryPath); + var destinationDir = Path.GetDirectoryName (destinationPath); + if (!Directory.Exists (destinationDir)) + Directory.CreateDirectory (destinationDir); + + entry.ExtractToFile (destinationPath, overwrite: true); + } + } + } + } else { + var tempName = Path.GetRandomFileName (); + var nestedTemp = Path.Combine (tempDir, tempName); + Directory.CreateDirectory (nestedTemp); + + //NOTE: using unzip to preserve file attributes var start = new ProcessStartInfo ("unzip", $"\"{sourceFile}\" -d \"{nestedTemp}\"") { CreateNoWindow = true, UseShellExecute = false, @@ -101,25 +120,26 @@ async TTask ExtractFile (string tempDir, string sourceFile, string relativeDestD Log.LogMessage (MessageImportance.Low, $"unzip \"{sourceFile}\" -d \"{nestedTemp}\""); var p = Process.Start (start); p.WaitForExit (); - } - var dirs = NoSubdirectory ? new string [] { nestedTemp } : Directory.EnumerateDirectories (nestedTemp, "*"); - - foreach (var dir in dirs) { - foreach (var fse in Directory.EnumerateFileSystemEntries (dir)) { - var name = Path.GetFileName (fse); - var destDir = string.IsNullOrEmpty (relativeDestDir) - ? destinationFolder - : Path.Combine (destinationFolder, relativeDestDir); - Directory.CreateDirectory (destDir); - var dest = Path.Combine (destDir, name); - Log.LogMessage (MessageImportance.Low, $"mv '{fse}' '{dest}'"); - if (Directory.Exists (fse)) - Process.Start ("/bin/mv", $@"""{fse}"" ""{dest}""").WaitForExit (); - else { - if (File.Exists (dest)) - File.Delete (dest); - File.Move (fse, dest); + + var dirs = NoSubdirectory ? new string [] { nestedTemp } : Directory.EnumerateDirectories (nestedTemp, "*"); + + foreach (var dir in dirs) { + foreach (var fse in Directory.EnumerateFileSystemEntries (dir)) { + var name = Path.GetFileName (fse); + var destDir = string.IsNullOrEmpty (relativeDestDir) + ? destinationFolder + : Path.Combine (destinationFolder, relativeDestDir); + Directory.CreateDirectory (destDir); + var dest = Path.Combine (destDir, name); + Log.LogMessage (MessageImportance.Low, $"mv '{fse}' '{dest}'"); + if (Directory.Exists (fse)) + Process.Start ("/bin/mv", $@"""{fse}"" ""{dest}""").WaitForExit (); + else { + if (File.Exists (dest)) + File.Delete (dest); + File.Move (fse, dest); + } } } }