diff --git a/.gitignore b/.gitignore index ff2e62b..d424323 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,5 @@ src/*.dll bin **/obj packages/ -TestResult-*.xml +TestResult*.xml .vs/ \ No newline at end of file diff --git a/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs b/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs index 5738fb1..6275edd 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs @@ -46,19 +46,13 @@ public IEnumerable GetBuildToolsPaths () var buildTools = Path.Combine (AndroidSdkPath, "build-tools"); if (Directory.Exists (buildTools)) { var preview = Directory.EnumerateDirectories (buildTools) - .Where(x => TryParseVersion (Path.GetFileName (x)) == null) + .Where(x => sdk.TryParseVersion (Path.GetFileName (x)) == null) .Select(x => x); foreach (var d in preview) yield return d; - var sorted = from p in Directory.EnumerateDirectories (buildTools) - let version = TryParseVersion (Path.GetFileName (p)) - where version != null - orderby version descending - select p; - - foreach (var d in sorted) + foreach (var d in sdk.GetSortedToolDirectoryPaths (buildTools)) yield return d; } var ptPath = Path.Combine (AndroidSdkPath, "platform-tools"); @@ -66,14 +60,6 @@ orderby version descending yield return ptPath; } - static Version TryParseVersion (string v) - { - Version version; - if (Version.TryParse (v, out version)) - return version; - return null; - } - public IEnumerable GetInstalledPlatformVersions (AndroidVersions versions) { if (versions == null) diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs index 12892b9..5ecf7f9 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs @@ -140,7 +140,36 @@ public virtual bool ValidateJavaSdkLocation (string loc) } /// - /// Checks that a value is the location of an Android SDK. + /// Searches all Android SDK locations for nested NDK installations. + /// + protected IEnumerable FindNdkPathsInAndroidSdkPaths () + { + string ndk; + var sdks = new List (); + if (!string.IsNullOrEmpty (AndroidSdkPath)) + sdks.Add (AndroidSdkPath); + + sdks.AddRange (AllAndroidSdks); + foreach (var sdk in sdks.Distinct ()) { + // Check for the "ndk-bundle" directory inside the SDK directories + if (Directory.Exists (ndk = Path.Combine (sdk, "ndk-bundle"))) { + if (ValidateAndroidNdkLocation (ndk)) { + yield return ndk; + } + } + // Check for any versioned "ndk/$(VERSION)" directory inside the SDK directories + if (Directory.Exists (ndk = Path.Combine (sdk, "ndk"))) { + foreach (var versionedNdk in GetSortedToolDirectoryPaths (ndk)) { + if (ValidateAndroidNdkLocation (versionedNdk)) { + yield return versionedNdk; + } + } + } + } + } + + /// + /// Checks that a value is the location of an Android NDK. /// public bool ValidateAndroidNdkLocation (string loc) { @@ -167,6 +196,23 @@ static string GetExecutablePath (string dir, string exe) return e; return exe; } + + public Version TryParseVersion (string v) + { + Version.TryParse (v, out Version version); + return version; + } + + public IEnumerable GetSortedToolDirectoryPaths (string topToolDirectory) + { + var sorted = from p in Directory.EnumerateDirectories (topToolDirectory) + let version = TryParseVersion (Path.GetFileName (p)) + where version != null + orderby version descending + select p; + + return sorted; + } } } diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs index 0d18f7b..fc92b4f 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs @@ -125,6 +125,10 @@ protected override IEnumerable GetAllAvailableAndroidNdks () if (ValidateAndroidNdkLocation (ndkDir)) yield return ndkDir; } + + // Check for NDK directories inside the SDK directories + foreach (var ndk in FindNdkPathsInAndroidSdkPaths ()) + yield return ndk; } 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 f5b2021..a53a6c1 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs @@ -237,17 +237,9 @@ protected override IEnumerable GetAllAvailableAndroidNdks () 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 NDK directories inside the SDK directories + foreach (var ndk in FindNdkPathsInAndroidSdkPaths ()) + yield return ndk; // Check for the key the user gave us in the VS/addin options foreach (var root in roots) diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs b/src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs index 50c6d9a..0ac089f 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Tests/AndroidSdkInfoTests.cs @@ -67,10 +67,8 @@ 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 oldPath = Environment.GetEnvironmentVariable ("PATH"); var logs = new StringWriter(); Action logger = (level, message) => { @@ -79,21 +77,58 @@ public void Ndk_PathInSdk() try { - var ndkPath = Path.Combine(sdk, "ndk-bundle"); - Directory.CreateDirectory(ndkPath); - Directory.CreateDirectory(Path.Combine(ndkPath, "toolchains")); - File.WriteAllText(Path.Combine(ndkPath, "ndk-stack.cmd"), ""); + if (!OS.IsWindows) + Environment.SetEnvironmentVariable ("PATH", "dummypath"); + var ndkPath = Path.Combine(sdk, "ndk-bundle"); + Directory.CreateDirectory (ndkPath); + CreateFauxAndroidNdkDirectory (ndkPath); var info = new AndroidSdkInfo(logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk); Assert.AreEqual(ndkPath, info.AndroidNdkPath, "AndroidNdkPath not found inside sdk!"); } finally { + if (!OS.IsWindows) + Environment.SetEnvironmentVariable ("PATH", oldPath); + Directory.Delete(root, recursive: true); } } + [Test] + public void VersionedNdk_PathInSdk() + { + CreateSdks (out string root, out string jdk, out string ndk, out string sdk); + var oldPath = Environment.GetEnvironmentVariable ("PATH"); + + var logs = new StringWriter (); + Action logger = (level, message) => { + logs.WriteLine ($"[{level}] {message}"); + }; + + try + { + if (!OS.IsWindows) + Environment.SetEnvironmentVariable ("PATH", "dummypath"); + + var ndkPath = Path.Combine (sdk, "ndk", "20.0.5594570"); + Directory.CreateDirectory (ndkPath); + Directory.CreateDirectory (Path.Combine (sdk, "ndk", "noversion")); + CreateFauxAndroidNdkDirectory (ndkPath); + var info = new AndroidSdkInfo (logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk); + Assert.AreEqual (ndkPath, info.AndroidNdkPath, "Versioned AndroidNdkPath not found inside sdk!"); + Assert.AreNotEqual (ndkPath, ndk, "The default NDK path created should not match the nested versioned NDK path!"); + } + finally + { + if (!OS.IsWindows) + Environment.SetEnvironmentVariable ("PATH", oldPath); + + Directory.Delete (root, recursive: true); + } + } + [Test] public void Constructor_SetValuesFromPath () {