diff --git a/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs b/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs index 5738fb1..4cf0ee4 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs @@ -52,11 +52,7 @@ public IEnumerable GetBuildToolsPaths () 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; + var sorted = SortedSubdirectoriesByVersion (buildTools); foreach (var d in sorted) yield return d; @@ -66,6 +62,15 @@ orderby version descending yield return ptPath; } + static IEnumerable SortedSubdirectoriesByVersion (string dir) + { + return from p in Directory.EnumerateDirectories (dir) + let version = TryParseVersion (Path.GetFileName (p)) + where version != null + orderby version descending + select p; + } + static Version TryParseVersion (string v) { Version version; @@ -185,5 +190,40 @@ public static void DetectAndSetPreferredJavaSdkPathToLatest (Action GetCommandLineToolsPaths (string preferredCommandLineToolsVersion) + { + if (!string.IsNullOrEmpty (preferredCommandLineToolsVersion)) { + var preferredDir = Path.Combine (AndroidSdkPath, "cmdline-tools", preferredCommandLineToolsVersion); + if (Directory.Exists (preferredDir)) + return new[] { preferredDir }.Concat (GetCommandLineToolsPaths ().Where (p => p != preferredDir)); + } + return GetCommandLineToolsPaths (); + } + + public IEnumerable GetCommandLineToolsPaths () + { + var cmdlineToolsDir = Path.Combine (AndroidSdkPath, "cmdline-tools"); + if (Directory.Exists (cmdlineToolsDir)) { + var latestDir = Path.Combine (cmdlineToolsDir, "latest"); + if (Directory.Exists (latestDir)) + yield return latestDir; + foreach (var d in SortedSubdirectoriesByVersion (cmdlineToolsDir)) { + var version = Path.GetFileName (d); + if (version == "latest") + continue; + yield return d; + } + } + var toolsDir = Path.Combine (AndroidSdkPath, "tools"); + if (Directory.Exists (toolsDir)) { + yield return toolsDir; + } + } } } diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs index 12892b9..b401fb6 100644 --- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs +++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs @@ -37,15 +37,10 @@ public AndroidSdkBase (Action logger) public string AndroidNdkPath { get; private set; } public string JavaSdkPath { get; private set; } public string JavaBinPath { get; private set; } - public string AndroidToolsPath { get; private set; } public string AndroidPlatformToolsPath { get; private set; } - public string AndroidToolsPathShort { get; private set; } public string AndroidPlatformToolsPathShort { get; private set; } public virtual string Adb { get; protected set; } = "adb"; - public virtual string Android { get; protected set; } = "android"; - public virtual string Emulator { get; protected set; } = "emulator"; - public virtual string Monitor { get; protected set; } = "monitor"; public virtual string ZipAlign { get; protected set; } = "zipalign"; public virtual string JarSigner { get; protected set; } = "jarsigner"; public virtual string KeyTool { get; protected set; } = "keytool"; @@ -76,13 +71,9 @@ public virtual void Initialize (string androidSdkPath = null, string androidNdkP } if (!string.IsNullOrEmpty (AndroidSdkPath)) { - AndroidToolsPath = Path.Combine (AndroidSdkPath, "tools"); - AndroidToolsPathShort = GetShortFormPath (AndroidToolsPath); AndroidPlatformToolsPath = Path.Combine (AndroidSdkPath, "platform-tools"); AndroidPlatformToolsPathShort = GetShortFormPath (AndroidPlatformToolsPath); } else { - AndroidToolsPath = null; - AndroidToolsPathShort = null; AndroidPlatformToolsPath = null; AndroidPlatformToolsPathShort = null; } @@ -98,9 +89,6 @@ public virtual void Initialize (string androidSdkPath = null, string androidNdkP // we need to look for extensions other than the default .exe|.bat // google have a habbit of changing them. Adb = GetExecutablePath (AndroidPlatformToolsPath, Adb); - Android = GetExecutablePath (AndroidToolsPath, Android); - Emulator = GetExecutablePath (AndroidToolsPath, Emulator); - Monitor = GetExecutablePath (AndroidToolsPath, Monitor); NdkStack = GetExecutablePath (AndroidNdkPath, NdkStack); } diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs index 50c6d9a..5b31f3b 100644 --- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs +++ b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs @@ -164,13 +164,74 @@ public void JdkDirectory_JavaHome () } } + [Test] + public void Sdk_GetCommandLineToolsPaths () + { + CreateSdks(out string root, out string jdk, out string ndk, out string sdk); + + var cmdlineTools = Path.Combine (sdk, "cmdline-tools"); + var latestToolsVersion = "latest"; + var toolsVersion = "2.1"; + var higherToolsVersion = "11.2"; + + void recreateCmdlineToolsDirectory () { + Directory.Delete (cmdlineTools, recursive: true); + Directory.CreateDirectory (cmdlineTools); + } + + try { + var info = new AndroidSdkInfo (androidSdkPath: sdk); + + // Test cmdline-tools path + recreateCmdlineToolsDirectory(); + CreateFauxAndroidSdkToolsDirectory (sdk, createToolsDir: true, toolsVersion: toolsVersion, createOldToolsDir: false); + var toolsPaths = info.GetCommandLineToolsPaths (); + + Assert.AreEqual (toolsPaths.Count (), 1, "Incorrect number of elements"); + Assert.AreEqual (toolsPaths.First (), Path.Combine (sdk, "cmdline-tools", toolsVersion), "Incorrect command line tools path"); + + // Test that cmdline-tools is preferred over tools + recreateCmdlineToolsDirectory(); + CreateFauxAndroidSdkToolsDirectory (sdk, createToolsDir: true, toolsVersion: latestToolsVersion, createOldToolsDir: true); + toolsPaths = info.GetCommandLineToolsPaths (); + + Assert.AreEqual (toolsPaths.Count (), 2, "Incorrect number of elements"); + Assert.AreEqual (toolsPaths.First (), Path.Combine (sdk, "cmdline-tools", latestToolsVersion), "Incorrect command line tools path"); + Assert.AreEqual (toolsPaths.Last (), Path.Combine (sdk, "tools"), "Incorrect tools path"); + + // Test sorting + recreateCmdlineToolsDirectory (); + CreateFauxAndroidSdkToolsDirectory (sdk, createToolsDir: true, toolsVersion: latestToolsVersion, createOldToolsDir: false); + CreateFauxAndroidSdkToolsDirectory (sdk, createToolsDir: true, toolsVersion: toolsVersion, createOldToolsDir: false); + CreateFauxAndroidSdkToolsDirectory (sdk, createToolsDir: true, toolsVersion: higherToolsVersion, createOldToolsDir: true); + toolsPaths = info.GetCommandLineToolsPaths (); + + var toolsPathsList = toolsPaths.ToList (); + Assert.AreEqual (toolsPaths.Count (), 4, "Incorrect number of elements"); + bool isOrderCorrect = toolsPathsList [0].Equals (Path.Combine (sdk, "cmdline-tools", latestToolsVersion), StringComparison.Ordinal) + && toolsPathsList [1].Equals (Path.Combine (sdk, "cmdline-tools", higherToolsVersion), StringComparison.Ordinal) + && toolsPathsList [2].Equals (Path.Combine (sdk, "cmdline-tools", toolsVersion), StringComparison.Ordinal) + && toolsPathsList [3].Equals (Path.Combine (sdk, "tools"), StringComparison.Ordinal); + + Assert.IsTrue (isOrderCorrect, "Tools order is not descending"); + } finally { + Directory.Delete (root, recursive: true); + } + } + static bool IsWindows => OS.IsWindows; - static void CreateSdks (out string root, out string jdk, out string ndk, out string sdk) + static string CreateRoot () { - root = Path.GetTempFileName (); + var root = Path.GetTempFileName (); File.Delete (root); Directory.CreateDirectory (root); + return root; + } + + static void CreateSdks (out string root, out string jdk, out string ndk, out string sdk) + { + root = CreateRoot (); ndk = Path.Combine (root, "ndk"); sdk = Path.Combine (root, "sdk"); @@ -185,17 +246,45 @@ static void CreateSdks (out string root, out string jdk, out string ndk, out str CreateFauxJavaSdkDirectory (jdk, "1.8.0", out var _, out var _); } - static void CreateFauxAndroidSdkDirectory (string androidSdkDirectory, string buildToolsVersion, ApiInfo [] apiLevels = null) + static void CreateFauxAndroidSdkToolsDirectory (string androidSdkDirectory, bool createToolsDir, string toolsVersion, bool createOldToolsDir) + { + if (createToolsDir) { + string androidSdkToolsPath = Path.Combine (androidSdkDirectory, "cmdline-tools", toolsVersion ?? "1.0"); + string androidSdkToolsBinPath = Path.Combine (androidSdkToolsPath, "bin"); + + Directory.CreateDirectory (androidSdkToolsPath); + Directory.CreateDirectory (androidSdkToolsBinPath); + + File.WriteAllText (Path.Combine (androidSdkToolsBinPath, IsWindows ? "lint.bat" : "lint"), ""); + } + + if (createOldToolsDir) { + string androidSdkToolsPath = Path.Combine (androidSdkDirectory, "tools"); + string androidSdkToolsBinPath = Path.Combine (androidSdkToolsPath, "bin"); + + Directory.CreateDirectory (androidSdkToolsPath); + Directory.CreateDirectory (androidSdkToolsBinPath); + + File.WriteAllText (Path.Combine (androidSdkToolsBinPath, IsWindows ? "lint.bat" : "lint"), ""); + } + + } + + static void CreateFauxAndroidSdkDirectory ( + string androidSdkDirectory, + string buildToolsVersion, + bool createToolsDir = true, + string toolsVersion = null, + bool createOldToolsDir = false, + ApiInfo[] apiLevels = null) { - var androidSdkToolsPath = Path.Combine (androidSdkDirectory, "tools"); - var androidSdkBinPath = Path.Combine (androidSdkToolsPath, "bin"); + CreateFauxAndroidSdkToolsDirectory (androidSdkDirectory, createToolsDir, toolsVersion, createOldToolsDir); + 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); @@ -203,7 +292,6 @@ static void CreateFauxAndroidSdkDirectory (string androidSdkDirectory, string bu 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++) {