From b29e5bd12bbc425b9bc797b545457fed712b5f5f Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 26 Feb 2021 14:14:29 -0600 Subject: [PATCH] [macOS] fix DirectoryNotFoundException on clean systems @PureWeen was hitting a problem building a .NET 6 app on macOS: Task "ResolveSdks" ... at System.IO.Enumeration.FileSystemEnumerator`1.CreateDirectoryHandle(String path, Boolean ignoreNotFound) at System.IO.Enumeration.FileSystemEnumerator`1.Init() at System.IO.Enumeration.FileSystemEnumerator`1..ctor(String directory, Boolean isNormalized, EnumerationOptions options) at System.IO.Enumeration.FileSystemEnumerable`1..ctor(String directory, FindTransform transform, EnumerationOptions options, Boolean isNormalized) at System.IO.Enumeration.FileSystemEnumerableFactory.UserDirectories(String directory, String expression, EnumerationOptions options) at System.IO.Directory.InternalEnumeratePaths(String path, String searchPattern, SearchTarget searchTarget, EnumerationOptions options) at Xamarin.Android.Tools.AndroidSdkBase.FindBestNDK(String androidSdkPath) in /Users/builder/azdo/_work/278/s/xamarin-android/external/xamarin-android-tools/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs:line 172 at Xamarin.Android.Tools.AndroidSdkBase.GetAllAvailableAndroidNdks()+MoveNext() in /Users/builder/azdo/_work/278/s/xamarin-android/external/xamarin-android-tools/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs:line 164 at Xamarin.Android.Tools.AndroidSdkBase.GetValidNdkPath(String ctorParam) in /Users/builder/azdo/_work/278/s/xamarin-android/external/xamarin-android-tools/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs:line 128 at Xamarin.Android.Tools.AndroidSdkBase.Initialize(String androidSdkPath, String androidNdkPath, String javaSdkPath) in /Users/builder/azdo/_work/278/s/xamarin-android/external/xamarin-android-tools/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs:line 71 at Xamarin.Android.Tools.AndroidSdkInfo..ctor(Action`2 logger, String androidSdkPath, String androidNdkPath, String javaSdkPath) in /Users/builder/azdo/_work/278/s/xamarin-android/external/xamarin-android-tools/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs:line 18 at Xamarin.Android.Tasks.MonoAndroidHelper.RefreshAndroidSdk(String sdkPath, String ndkPath, String javaPath, TaskLoggingHelper logHelper) at Xamarin.Android.Tasks.ResolveSdks.RunTask() at Microsoft.Android.Build.Tasks.AndroidTask.Execute() in /Users/builder/azdo/_work/278/s/xamarin-android/external/xamarin-android-tools/src/Microsoft.Android.Build.BaseTasks/AndroidTask.cs:line 17 This was a relatively new Mac, that didn't have an Android NDK installed at all. A way to workaround the problem was to create a directory that did not exist: mkdir -p ~/Library/Android/sdk It appears this problem was introduced in b2d9fdf8: * `~/Library/Android/sdk` is returned form `GetAllAvailableAndroidNdks()`: https://github.com/xamarin/xamarin-android-tools/blob/b2d9fdf8782875ffb63da48cf8e0b385b04f7c25/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs#L113-L115 * `GetAllAvailableAndroidNdks()` calls `GetAllAvailableAndroidSdks()` looking for any `ndk-bundle` folders it can find. * `FindBestNDK()` is passed a directory that doesn't exist, and the `Directory.EnumerateDirectories()` call will throw: https://github.com/xamarin/xamarin-android-tools/blob/b2d9fdf8782875ffb63da48cf8e0b385b04f7c25/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs#L172 The fix here is to check `Directory.Exists()` in `FindBestNDK()`, as the values from `GetSdkFromEnvironmentVariables()` may not exist either. I was able to add a test for this scenario by adding an invalid directory to `$ANDROID_HOME`. --- .../Sdks/AndroidSdkBase.cs | 11 ++++++++-- .../AndroidSdkInfoTests.cs | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs index 59fc390..b39b75f 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs @@ -152,7 +152,7 @@ protected virtual IEnumerable GetAllAvailableAndroidNdks () // Look in PATH foreach (var ndkStack in ProcessUtils.FindExecutablesInPath (NdkStack)) { var ndkDir = Path.GetDirectoryName (ndkStack); - if (ndkDir == null) + if (string.IsNullOrEmpty (ndkDir)) continue; yield return ndkDir; } @@ -161,12 +161,19 @@ protected virtual IEnumerable GetAllAvailableAndroidNdks () foreach (var sdk in GetAllAvailableAndroidSdks ()) { if (sdk == AndroidSdkPath) continue; - yield return FindBestNDK (sdk); + var ndkDir = FindBestNDK (sdk); + if (string.IsNullOrEmpty (ndkDir)) + continue; + yield return ndkDir; } } string FindBestNDK (string androidSdkPath) { + if (!Directory.Exists (androidSdkPath)) { + return String.Empty; + } + var ndkInstances = new SortedDictionary (Comparer.Create ((Version l, Version r) => r.CompareTo (l))); foreach (string ndkPath in Directory.EnumerateDirectories (androidSdkPath, "ndk*", SearchOption.TopDirectoryOnly)) { diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs index 7efcaa2..54dc353 100644 --- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs +++ b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs @@ -146,6 +146,28 @@ public void Ndk_PathInSdk() } } + [Test] + public void Ndk_AndroidSdkDoesNotExist () + { + CreateSdks (out string root, out string jdk, out string ndk, out string sdk); + + Action logger = (level, message) => { + Console.WriteLine ($"[{level}] {message}"); + if (level == TraceLevel.Error) + Assert.Fail (message); + }; + + var oldAndroidHome = Environment.GetEnvironmentVariable ("ANDROID_HOME"); + try { + Environment.SetEnvironmentVariable ("ANDROID_HOME", "/i/dont/exist"); + // Check that this doesn't throw + new AndroidSdkInfo (logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk); + } finally { + Environment.SetEnvironmentVariable ("ANDROID_HOME", oldAndroidHome); + Directory.Delete (root, recursive: true); + } + } + [Test] public void Constructor_SetValuesFromPath () {