diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs index 1b10df1..820c81c 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs @@ -10,22 +10,21 @@ namespace Xamarin.Android.Tools abstract class AndroidSdkBase { string[]? allAndroidSdks; - string[]? allAndroidNdks; public string[] AllAndroidSdks { get { - if (allAndroidSdks == null) - allAndroidSdks = GetAllAvailableAndroidSdks ().Distinct ().ToArray (); + if (allAndroidSdks == null) { + var dirs = new List (); + dirs.Add (AndroidSdkPath); + dirs.AddRange (GetAllAvailableAndroidSdks ()); + allAndroidSdks = dirs.Where (d => ValidateAndroidSdkLocation (d)) + .Select (d => d!) + .Distinct () + .ToArray (); + } return allAndroidSdks; } } - public string[] AllAndroidNdks { - get { - if (allAndroidNdks == null) - allAndroidNdks = GetAllAvailableAndroidNdks ().Distinct ().ToArray (); - return allAndroidNdks; - } - } public readonly Action Logger; @@ -57,13 +56,10 @@ public AndroidSdkBase (Action logger) public virtual void Initialize (string? androidSdkPath = null, string? androidNdkPath = null, string? javaSdkPath = null) { - androidSdkPath = androidSdkPath ?? PreferedAndroidSdkPath; - androidNdkPath = androidNdkPath ?? PreferedAndroidNdkPath; - javaSdkPath = javaSdkPath ?? PreferedJavaSdkPath; + AndroidSdkPath = GetValidPath (ValidateAndroidSdkLocation, androidSdkPath, () => PreferedAndroidSdkPath, () => GetAllAvailableAndroidSdks ()); + JavaSdkPath = GetValidPath (ValidateJavaSdkLocation, javaSdkPath, () => PreferedJavaSdkPath, () => GetJavaSdkPaths ()); - AndroidSdkPath = ValidateAndroidSdkLocation (androidSdkPath) ? androidSdkPath : AllAndroidSdks.FirstOrDefault (); - AndroidNdkPath = ValidateAndroidNdkLocation (androidNdkPath) ? androidNdkPath : AllAndroidNdks.FirstOrDefault (); - JavaSdkPath = ValidateJavaSdkLocation (javaSdkPath) ? javaSdkPath : GetJavaSdkPath (); + AndroidNdkPath = GetValidNdkPath (androidNdkPath); if (!string.IsNullOrEmpty (JavaSdkPath)) { JavaBinPath = Path.Combine (JavaSdkPath, "bin"); @@ -93,11 +89,60 @@ public virtual void Initialize (string? androidSdkPath = null, string? androidNd NdkStack = GetExecutablePath (AndroidNdkPath, NdkStack); } + static string? GetValidPath (Func pathValidator, string? ctorParam, Func getPreferredPath, Func> getAllPaths) + { + if (pathValidator (ctorParam)) + return ctorParam; + ctorParam = getPreferredPath (); + if (pathValidator (ctorParam)) + return ctorParam; + foreach (var path in getAllPaths ()) { + if (pathValidator (path)) + return path; + } + return null; + } + + string? GetValidNdkPath (string? ctorParam) + { + if (ValidateAndroidNdkLocation (ctorParam)) + return ctorParam; + if (AndroidSdkPath != null) { + string bundle = Path.Combine (AndroidSdkPath, "ndk-bundle"); + if (Directory.Exists (bundle) && ValidateAndroidNdkLocation (bundle)) + return bundle; + } + ctorParam = PreferedAndroidNdkPath; + if (ValidateAndroidNdkLocation (ctorParam)) + return ctorParam; + foreach (var path in GetAllAvailableAndroidNdks ()) { + if (ValidateAndroidNdkLocation (path)) + return path; + } + return null; + } + protected abstract IEnumerable GetAllAvailableAndroidSdks (); - protected abstract IEnumerable GetAllAvailableAndroidNdks (); - protected abstract string? GetJavaSdkPath (); protected abstract string GetShortFormPath (string path); + protected virtual IEnumerable GetAllAvailableAndroidNdks () + { + // Look in PATH + foreach (var ndkStack in ProcessUtils.FindExecutablesInPath (NdkStack)) { + var ndkDir = Path.GetDirectoryName (ndkStack); + if (ndkDir == null) + continue; + yield return ndkDir; + } + + // Check for the "ndk-bundle" directory inside other SDK directories + foreach (var sdk in GetAllAvailableAndroidSdks ()) { + if (sdk == AndroidSdkPath) + continue; + yield return Path.Combine (sdk, "ndk-bundle"); + } + } + public abstract void SetPreferredAndroidSdkPath (string? path); public abstract void SetPreferredJavaSdkPath (string? path); public abstract void SetPreferredAndroidNdkPath (string? path); @@ -108,6 +153,12 @@ public string NdkHostPlatform { get { return IsNdk64Bit ? NdkHostPlatform64Bit : NdkHostPlatform32Bit; } } + IEnumerable GetJavaSdkPaths () + { + return JdkInfo.GetKnownSystemJdkInfos (Logger) + .Select (jdk => jdk.HomePath); + } + /// /// Checks that a value is the location of an Android SDK. /// diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs index 12bd536..34836f3 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs @@ -98,33 +98,15 @@ protected override IEnumerable GetAllAvailableAndroidSdks () // Strip off "platform-tools" var dir = Path.GetDirectoryName (path); - if (ValidateAndroidSdkLocation (dir)) - yield return dir; + if (dir == null) + continue; + + yield return dir; } // Check some hardcoded paths for good measure var macSdkPath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), "Library", "Android", "sdk"); - if (ValidateAndroidSdkLocation (macSdkPath)) - yield return macSdkPath; - } - - protected override string? GetJavaSdkPath () - { - return JdkInfo.GetKnownSystemJdkInfos (Logger).FirstOrDefault ()?.HomePath; - } - - protected override IEnumerable GetAllAvailableAndroidNdks () - { - var preferedNdkPath = PreferedAndroidNdkPath; - if (!string.IsNullOrEmpty (preferedNdkPath)) - yield return preferedNdkPath!; - - // Look in PATH - foreach (var ndkStack in ProcessUtils.FindExecutablesInPath (NdkStack)) { - var ndkDir = Path.GetDirectoryName (ndkStack); - if (ValidateAndroidNdkLocation (ndkDir)) - yield return ndkDir; - } + yield return macSdkPath; } protected override string GetShortFormPath (string path) diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs index bf02640..59b2082 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs @@ -102,14 +102,7 @@ protected override IEnumerable GetAllAvailableAndroidSdks () }; foreach (var basePath in paths) if (Directory.Exists (basePath)) - if (ValidateAndroidSdkLocation (basePath)) - yield return basePath; - } - - protected override string? GetJavaSdkPath () - { - var jdk = JdkInfo.GetKnownSystemJdkInfos (Logger).FirstOrDefault (); - return jdk?.HomePath; + yield return basePath; } internal static IEnumerable GetJdkInfos (Action logger) @@ -223,24 +216,13 @@ private static IEnumerable GetOracleJdkPaths () protected override IEnumerable GetAllAvailableAndroidNdks () { + var roots = new[] { RegistryEx.CurrentUser, RegistryEx.LocalMachine }; var wow = RegistryEx.Wow64.Key32; var regKey = GetMDRegistryKey (); Logger (TraceLevel.Info, "Looking for Android NDK..."); - // Check for the "ndk-bundle" directory inside the SDK directories - string ndk; - - var sdks = GetAllAvailableAndroidSdks().ToList(); - if (!string.IsNullOrEmpty(AndroidSdkPath)) - sdks.Add (AndroidSdkPath!); - - foreach(var sdk in sdks.Distinct()) - if (Directory.Exists(ndk = Path.Combine(sdk, "ndk-bundle"))) - if (ValidateAndroidNdkLocation(ndk)) - yield return ndk; - // Check for the key the user gave us in the VS/addin options foreach (var root in roots) if (CheckRegistryKeyForExecutable (root, regKey, MDREG_ANDROID_NDK, wow, ".", NdkStack)) @@ -265,6 +247,10 @@ protected override IEnumerable GetAllAvailableAndroidNdks () foreach (var dir in Directory.GetDirectories (basePath, "android-ndk-r*")) if (ValidateAndroidNdkLocation (dir)) yield return dir; + + foreach (var dir in base.GetAllAvailableAndroidNdks ()) { + yield return dir; + } } protected override string GetShortFormPath (string path) diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs index a02ffd6..28aad14 100644 --- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs +++ b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs @@ -67,9 +67,6 @@ public void Constructor_Paths () [Test] public void Ndk_PathInSdk() { - if (!OS.IsWindows) - Assert.Ignore("This only works in Windows"); - CreateSdks(out string root, out string jdk, out string ndk, out string sdk); var logs = new StringWriter(); @@ -79,10 +76,11 @@ public void Ndk_PathInSdk() try { + var extension = OS.IsWindows ? ".cmd" : ""; var ndkPath = Path.Combine(sdk, "ndk-bundle"); Directory.CreateDirectory(ndkPath); Directory.CreateDirectory(Path.Combine(ndkPath, "toolchains")); - File.WriteAllText(Path.Combine(ndkPath, "ndk-stack.cmd"), ""); + File.WriteAllText(Path.Combine(ndkPath, $"ndk-stack{extension}"), ""); var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk);