From 590696fa667b45e24e9c06cdfe424ec5fd6865d3 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 27 Jul 2018 15:20:17 -0400 Subject: [PATCH] [Xamarin.Android.Tools.AndroidSdk] Revert JDK validation Context: https://github.com/xamarin/xamarin-android/pull/2004 Context: https://jenkins.mono-project.com/job/xamarin-android-pr-builder/3656/testReport/junit/Xamarin.Android.Build.Tests/ResolveSdksTaskTests/ResolveSdkTiming___Debug/ Before commit 75530565, the only validation performed on the `AndroidSdkInfo`'s `javaSdkPath` parameter was "does `{javaSdkPath}/bin/jarsigner` exist? This is the world the [xamarin-android unit tests assumed][0], as it would create `{javaSdkPath}/bin/jarsigner` and `{javaSdkPath}/bin/javac.bash` (among others), but *not* `{javaSdkPath/bin/javac`. Then came commit 75530565, which altered `AndroidSdkUnix.ValidateJavaSdkLocation()` semantics so that it now *required* the presence of `{javaSdkPath}/bin/javac`. This changed caused the xamarin-android unit tests to fail: JavaSdkPath should be /Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/TestDebug/temp/ResolveSdkTiming/jdk Expected string length 63 but was 115. Strings differ at index 1. Expected: "/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home" But was: "/Users/builder/jenkins/workspace/xamarin-android-pr-builder/x..." ------------^ The "expected" and "actual" values are reversed; the actual problem is that the `javaSdkPath` value provided to the `AndroidSdkInfo` constructor -- `/Users/builder/jenkins/workspace/xamarin-android-pr-builder/xamarin-android/bin/TestDebug/temp/ResolveSdkTiming/jdk` -- is "ignored", because it doesn't pass validation, prompting `AndroidSdkInfo` to call `AndroidSdkUnix.GetJavaSdkPath()`, which returns a "system" location, `/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home`. As such, the original `javaSdkPath` value is not preserved and returned by the `AndroidSdkInfo.JavaSdkPath` property. Fix this by *removing* the `AndroidSdkUnix.ValidateJavaSdkLocation()` method: it doesn't appear to actually be useful in this instance, as the base `AndroidSdkBase.ValidateJavaSdkLocation()` already checks for the presence of `{javaSdkPath}/bin/jarsigner`. [0]: https://github.com/xamarin/xamarin-android/blob/997b8904889d371610026c1802a8e3403d7d2c96/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/BaseTest.cs#L220-L235 --- .../Sdks/AndroidSdkUnix.cs | 11 -- .../Tests/AndroidSdkInfoTests.cs | 139 ++++++++++++++++++ 2 files changed, 139 insertions(+), 11 deletions(-) diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs index eba5184..be0d5fb 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs @@ -112,17 +112,6 @@ protected override string GetJavaSdkPath () return JdkInfo.GetKnownSystemJdkInfos (Logger).FirstOrDefault ()?.HomePath; } - public override bool ValidateJavaSdkLocation (string loc) - { - var result = base.ValidateJavaSdkLocation (loc); - - if (result) { - return File.Exists (Path.Combine (loc, "bin", "javac")); - } - - return result; - } - protected override IEnumerable GetAllAvailableAndroidNdks () { var preferedNdkPath = PreferedAndroidNdkPath; diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs b/src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs index 2190f23..887e4e8 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; +using System.Text; using NUnit.Framework; @@ -15,5 +17,142 @@ public void Constructor_NullLogger () Action logger = null; Assert.Throws (() => new AndroidSdkInfo (logger)); } + + [Test] + public void Constructor_Paths () + { + var root = Path.GetTempFileName (); + File.Delete (root); + Directory.CreateDirectory (root); + + var sdk = Path.Combine (root, "sdk"); + var jdk = Path.Combine (root, "jdk"); + + Directory.CreateDirectory (sdk); + Directory.CreateDirectory (jdk); + + CreateFauxAndroidSdkDirectory (sdk, "26.0.0"); + CreateFauxJavaSdkDirectory (jdk, "1.8.0", out var _, out var _); + + var logs = new StringWriter (); + Action logger = (level, message) => { + logs.WriteLine ($"[{level}] {message}"); + }; + var info = new AndroidSdkInfo (logger, androidSdkPath: sdk, javaSdkPath: jdk, androidNdkPath: null); + + Assert.AreEqual (sdk, info.AndroidSdkPath, "AndroidSdkPath not preserved!"); + Assert.AreEqual (jdk, info.JavaSdkPath, "JavaSdkPath not preserved!"); + } + + static bool IsWindows => OS.IsWindows; + + static void CreateFauxAndroidSdkDirectory (string androidSdkDirectory, string buildToolsVersion, ApiInfo [] apiLevels = null) + { + var androidSdkToolsPath = Path.Combine (androidSdkDirectory, "tools"); + var androidSdkBinPath = Path.Combine (androidSdkToolsPath, "bin"); + var androidSdkPlatformToolsPath = Path.Combine (androidSdkDirectory, "platform-tools"); + var androidSdkPlatformsPath = Path.Combine (androidSdkDirectory, "platforms"); + var androidSdkBuildToolsPath = Path.Combine (androidSdkDirectory, "build-tools", buildToolsVersion); + + Directory.CreateDirectory (androidSdkDirectory); + Directory.CreateDirectory (androidSdkToolsPath); + Directory.CreateDirectory (androidSdkBinPath); + Directory.CreateDirectory (androidSdkPlatformToolsPath); + Directory.CreateDirectory (androidSdkPlatformsPath); + Directory.CreateDirectory (androidSdkBuildToolsPath); + + File.WriteAllText (Path.Combine (androidSdkPlatformToolsPath, IsWindows ? "adb.exe" : "adb"), ""); + File.WriteAllText (Path.Combine (androidSdkBuildToolsPath, IsWindows ? "zipalign.exe" : "zipalign"), ""); + File.WriteAllText (Path.Combine (androidSdkBuildToolsPath, IsWindows ? "aapt.exe" : "aapt"), ""); + File.WriteAllText (Path.Combine (androidSdkToolsPath, IsWindows ? "lint.bat" : "lint"), ""); + + List defaults = new List (); + for (int i = 10; i < 26; i++) { + defaults.Add (new ApiInfo () { + Id = i.ToString (), + }); + } + foreach (var level in ((IEnumerable) apiLevels) ?? defaults) { + var dir = Path.Combine (androidSdkPlatformsPath, $"android-{level.Id}"); + Directory.CreateDirectory(dir); + File.WriteAllText (Path.Combine (dir, "android.jar"), ""); + } + } + + struct ApiInfo { + public string Id; + } + + protected string CreateFauxJavaSdkDirectory (string javaPath, string javaVersion, out string javaExe, out string javacExe) + { + javaExe = IsWindows ? "Java.cmd" : "java.bash"; + javacExe = IsWindows ? "Javac.cmd" : "javac.bash"; + var jarSigner = IsWindows ? "jarsigner.exe" : "jarsigner"; + var javaBinPath = Path.Combine (javaPath, "bin"); + + Directory.CreateDirectory (javaBinPath); + + CreateFauxJavaExe (Path.Combine (javaBinPath, javaExe), javaVersion); + CreateFauxJavacExe (Path.Combine (javaBinPath, javacExe), javaVersion); + + File.WriteAllText (Path.Combine (javaBinPath, jarSigner), ""); + return javaPath; + } + + void CreateFauxJavaExe (string javaExeFullPath, string version) + { + var sb = new StringBuilder (); + if (IsWindows) { + sb.AppendLine ("@echo off"); + sb.AppendLine ($"echo java version \"{version}\""); + sb.AppendLine ($"echo Java(TM) SE Runtime Environment (build {version}-b13)"); + sb.AppendLine ($"echo Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)"); + } else { + sb.AppendLine ("#!/bin/bash"); + sb.AppendLine ($"echo \"java version \\\"{version}\\\"\""); + sb.AppendLine ($"echo \"Java(TM) SE Runtime Environment (build {version}-b13)\""); + sb.AppendLine ($"echo \"Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)\""); + } + File.WriteAllText (javaExeFullPath, sb.ToString ()); + if (!IsWindows) { + Exec ("chmod", $"u+x \"{javaExeFullPath}\""); + } + } + + void CreateFauxJavacExe (string javacExeFullPath, string version) + { + var sb = new StringBuilder (); + if (IsWindows) { + sb.AppendLine ("@echo off"); + sb.AppendLine ($"echo javac {version}"); + } else { + sb.AppendLine ("#!/bin/bash"); + sb.AppendLine ($"echo \"javac {version}\""); + } + File.WriteAllText (javacExeFullPath, sb.ToString ()); + if (!IsWindows) { + Exec ("chmod", $"u+x \"{javacExeFullPath}\""); + } + } + + protected void Exec (string exe, string args) + { + var psi = new ProcessStartInfo { + FileName = exe, + Arguments = args, + UseShellExecute = false, + RedirectStandardInput = false, + RedirectStandardOutput = false, + RedirectStandardError = false, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + + }; + var proc = Process.Start (psi); + if (!proc.WaitForExit ((int) TimeSpan.FromSeconds(30).TotalMilliseconds)) { + proc.Kill (); + proc.WaitForExit (); + } + } } }