From 26e4019b6fa996e310a1bd2780bd65de34c9b6ea Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Wed, 11 Dec 2024 14:31:58 -0500 Subject: [PATCH 1/6] [build] Generate `workload-dependencies.json` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Context: [`Releases.json` loop][0] Context: https://github.com/xamarin/xamarin-macios/pull/21779#discussion_r1876519440 There is a desire to have the .NET Workloads have a machine readable description of what dependencies they require in order to run, in order to facilitate tooling that would check for these dependencies. Add `tools/workload-dependencies`, a new tool which parses a "Xamarin Manifest" to generate `workload-dependencies.json`. The "canonical" location for the "Xamarin Manifest" is within `external/android-platform-support/Feeds/AndroidManifestFeed_d17.12.xml`; failing that, can be used. Output of the tool is a JSON document specifying ther required JDK and Android SDK packages which the .NET for Android workload requires: { "microsoft.net.sdk.android": { "workload": { "alias": [ "android" ], "version": "35.0.100" }, "jdk": { "version": "[17.0,18.0)", "recommendedVersion": "17.0.12" }, "androidsdk": { "packages": [ { "desc": "Android SDK Build-Tools 35", "sdkPackage": { "id": "build-tools;*", "version": "[30.0.2,30.0.3,31.0.0,32.0.0,33.0.0,33.0.1,33.0.2,33.0.3,34.0.0,35.0.0]", "recommendedId": "build-tools;35.0.0", "recommendedVersion": "35.0.0" }, "optional": "false" }, { "desc": "Android SDK Command-line Tools", "sdkPackage": { "id": "cmdline-tools;*", "version": "[5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0]", "recommendedId": "cmdline-tools;13.0", "recommendedVersion": "13.0" }, "optional": "false" }, { "desc": "Android SDK Platform 35", "sdkPackage": { "id": "platforms;android-*", "version": "[2,2,3,2,3,2,3,6,5,3,1,1,3,3,1]", "recommendedId": "platforms;android-35", "recommendedVersion": "1" }, "optional": "false" }, { "desc": "Android SDK Platform-Tools", "sdkPackage": { "id": "platform-tools", "version": "[33.0.2,33.0.3,34.0.1,34.0.3,34.0.4,34.0.5,35.0.1,35.0.2]", "recommendedId": "platform-tools", "recommendedVersion": "35.0.2" }, "optional": "false" }, … ] } } } [0]: https://loop.cloud.microsoft/p/eyJ1IjoiaHR0cHM6Ly9taWNyb3NvZnQuc2hhcmVwb2ludC1kZi5jb20vc2l0ZXMvYzIyZmVjMDMtN2I4OS00OTJhLTgzNzQtZmZjMTI4YjMwMWRhP25hdj1jejBsTWtaemFYUmxjeVV5Um1NeU1tWmxZekF6TFRkaU9Ea3RORGt5WVMwNE16YzBMV1ptWXpFeU9HSXpNREZrWVNaa1BXSWxNakZXTUhSeU9XY3dRbk5WYlhVdFJWUjNRVEZNY0dOSmQwdG1VVEZUZFVFeFRuRk5XbVZ3TUhVd1dUaEhkVVpKVlRSUGIxWnlVMWxoZFRaT2RFODRTamhISm1ZOU1ERlhSelkwU0RNMU56TlZRbEpITWs1TU1rSkdTemRZV1ZCWFJqSlNTRVJQVENaalBTVXlSaVpoUFV4dmIzQkJjSEFtY0QwbE5EQm1iSFZwWkhnbE1rWnNiMjl3TFhCaFoyVXRZMjl1ZEdGcGJtVnlKbmc5SlRkQ0pUSXlkeVV5TWlVelFTVXlNbFF3VWxSVlNIaDBZVmRPZVdJelRuWmFibEYxWXpKb2FHTnRWbmRpTW14MVpFTXhhMXBwTldwaU1qRTRXV2xHVjAxSVVubFBWMk4zVVc1T1ZtSllWWFJTVmxJelVWUkdUV05IVGtwa01IUnRWVlJHVkdSVlJYaFVia1pPVjIxV2QwMUlWWGRYVkdoSVpGVmFTbFpVVWxCaU1WcDVWVEZzYUdSVVdrOWtSVGcwVTJwb1NHWkVRWGhXTUdNeVRrVm5lazU2VGtwVU1WRXdWMnQwUmxGNldrdFRSbXhaVlRCYVVWUlZhRlJXUlVaRFYyeEZKVE5FSlRJeUpUSkRKVEl5YVNVeU1pVXpRU1V5TWprNE5HUXhZMlpoTFRnMVpXUXROR1kyWXkxaU9EWmlMVFJtTXpZMU1EQXlaak5tTnlVeU1pVTNSQT09In0%3D?ct=1728330820992& --- .../Microsoft.NET.Sdk.Android.proj | 11 + tools/workload-dependencies/Program.cs | 338 ++++++++++++++++++ .../workload-dependencies.csproj | 15 + 3 files changed, 364 insertions(+) create mode 100644 tools/workload-dependencies/Program.cs create mode 100644 tools/workload-dependencies/workload-dependencies.csproj diff --git a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj index 3d5dd76a499..d978402ee20 100644 --- a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj +++ b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj @@ -43,9 +43,20 @@ about the various Microsoft.Android workloads. Replacements="@NET_PREVIOUS_VERSION@=$(AndroidNetPreviousVersion)"> + + <_AndroidPlatformSupportFeed>$(MSBuildThisFileDirectory)/../../external/android-platform-support/Feeds/AndroidManifestFeed_d17.12.xml + <_Feed Condition=" Exists($(_AndroidPlatformSupportFeed)) ">$(_AndroidPlatformSupportFeed) + <_Feed Condition=" '$(_Feed)' == '' ">https://aka.ms/AndroidManifestFeed/d17-12 + <_Project>$(MSBuildThisFileDirectory)/../../tools/workload-dependencies/workload-dependencies.csproj + $(OutputPath)workload-manifest\workload-dependencies.json + + + + <_PackageFiles Include="$(WorkloadManifestJsonPath)" PackagePath="data" /> <_PackageFiles Include="$(WorkloadManifestTargetsPath)" PackagePath="data" /> + <_PackageFiles Include="$(WorkloadDependenciesPath)" PackagePath="data" /> diff --git a/tools/workload-dependencies/Program.cs b/tools/workload-dependencies/Program.cs new file mode 100644 index 00000000000..575e1110f1c --- /dev/null +++ b/tools/workload-dependencies/Program.cs @@ -0,0 +1,338 @@ +using System.Net.Http; +using System.Xml.Linq; + +using Mono.Options; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +const string AppName = "release-json"; + +var RequiredPackages = new HashSet { + "platform-tools", + "cmdline-tools", + "build-tool", + "platform", +}; + +var help = false; +var feed = (string?) null; +var output = (string?) null; +int verbosity = 0; +var workloadVersion = (string?) null; + +var options = new OptionSet { + "Generate `release.json` from Feed XML file.", + { "i|feed=", + "The {PATH} to the Feed XML file.", + v => feed = v }, + { "o|output=", + "The {PATH} to the output release.json file.", + v => output = v }, + { "workload-version=", + "The {VERSION} of the workload to generate.", + v => workloadVersion = v }, + { "v|verbose:", + "Set internal message verbosity", + (int? v) => verbosity = v.HasValue ? v.Value : verbosity + 1 }, + { "h|help", + "Show this help message and exit", + v => help = v != null }, +}; + +XDocument doc; + +try { + options.Parse (args); + + if (help) { + options.WriteOptionDescriptions (Console.Out); + return; + } + + if (string.IsNullOrEmpty (feed)) { + Console.Error.WriteLine ($"{AppName}: --feed is required."); + Console.Error.WriteLine ($"{AppName}: Use --help for more information."); + return; + } + doc = XDocument.Parse (await GetFeedContents (feed)); + if (doc.Root == null) { + throw new InvalidOperationException ("Missing root element in XML feed."); + } +} +catch (OptionException e) { + Console.Error.WriteLine ($"{AppName}: {e.Message}"); + if (verbosity > 0) { + Console.Error.WriteLine (e.ToString ()); + } + return; +} +catch (System.Xml.XmlException e) { + Console.Error.WriteLine ($"{AppName}: invalid `--feed=PATH` value. {e.Message}"); + if (verbosity > 0) { + Console.Error.WriteLine (e.ToString ()); + } + return; +} + +var PackageCreators = new Dictionary>> { + ["addon"] = CreateAddonPackageEntries, + ["extra"] = CreateExtraPackageEntries, + ["jdk"] = doc => Array.Empty (), + ["licenses"] = doc => Array.Empty (), + ["system-image"] = CreateSystemImagePackageEntries, +}; + +var release = new JObject { + new JProperty ("microsoft.net.sdk.android", new JObject { + CreateWorkloadProperty (doc), + CreateJdkProperty (doc), + new JProperty ("androidsdk", new JObject { + new JProperty ("packages", CreatePackagesArray (doc)), + }), + }), +}; + +using var writer = CreateWriter (); +release.WriteTo (writer); +writer.Flush (); + +async Task GetFeedContents (string feed) +{ + if (File.Exists (feed)) { + return File.ReadAllText (feed); + } + if (Uri.TryCreate (feed, UriKind.Absolute, out var uri)) { + return await GetFeedContentsFromUri (uri); + } + throw new NotSupportedException ($"Don't know what to do with --feed={feed}"); +} + +async Task GetFeedContentsFromUri (Uri feed) +{ + using var client = new HttpClient (); + var response = await client.GetAsync (feed); + return await response.Content.ReadAsStringAsync (); +} + +JsonWriter CreateWriter () +{ + var w = string.IsNullOrEmpty (output) + ? new JsonTextWriter (Console.Out) { CloseOutput = false} + : new JsonTextWriter (File.CreateText (output)) { CloseOutput = true }; + w.Formatting = Formatting.Indented; + return w; +} + +JProperty CreateWorkloadProperty (XDocument doc) +{ + var contents = new JObject ( + new JProperty ("alias", new JArray ("android"))); + if (!string.IsNullOrEmpty (workloadVersion)) + contents.Add (new JProperty ("version", workloadVersion)); + return new JProperty ("workload", contents); +} + +JProperty CreateJdkProperty (XDocument doc) +{ + var latestRevision = GetLatestRevision (doc, "jdk"); + var contents = new JObject ( + new JProperty ("version", "[17.0,18.0)")); + if (!string.IsNullOrEmpty (latestRevision)) + contents.Add (new JProperty ("recommendedVersion", latestRevision)); + return new JProperty ("jdk", contents); +} + +IEnumerable GetSupportedElements (XDocument doc, string element) +{ + if (doc.Root == null) { + return Array.Empty (); + } + return doc.Root.Elements (element) + .Where (e => + string.Equals ("False", e.ReqAttr ("obsolete"), StringComparison.OrdinalIgnoreCase) && + string.Equals ("False", e.ReqAttr ("preview"), StringComparison.OrdinalIgnoreCase)); +} + +IEnumerable<(XElement Element, string Revision)> GetByRevisions (XDocument doc, string element) +{ + return GetSupportedElements (doc, element) + .OrderByRevision (); +} + +string? GetLatestRevision (XDocument doc, string element) +{ + return GetByRevisions (doc, element) + .LastOrDefault () + .Revision; +} + +IEnumerable CreateAddonPackageEntries (XDocument doc) +{ + var allAddons = GetSupportedElements (doc, "addon").ToList () + .OrderBy (e => e.ReqAttr ("path")); + var paths = allAddons + .Select (e => GetEntryId (e)) + .Distinct (); + foreach (var path in paths) { + var addons = allAddons + .Where (e => GetEntryId (e) == path); + var version = string.Join (",", addons.Select (e => e.ReqAttr ("revision"))); + var latest = addons.Last (); + var entry = new JObject { + new JProperty ("desc", latest.ReqAttr ("description")), + new JProperty ("sdkPackage", new JObject { + new JProperty ("id", path), + new JProperty ("version", "[" + version + "]"), + new JProperty ("recommendedId", latest.ReqAttr ("path")), + new JProperty ("recommendedVersion", latest.ReqAttr ("revision")), + }), + new JProperty ("optional", "true"), + }; + yield return entry; + } +} + +IEnumerable CreateExtraPackageEntries (XDocument doc) +{ + var allExtras = GetByRevisions (doc, "extra").ToList (); + var paths = allExtras + .Select (e => e.Element.ReqAttr ("path")) + .Distinct (); + foreach (var path in paths) { + var extras = allExtras + .Where (e => e.Element.ReqAttr ("path") == path); + var version = string.Join (",", extras.Select (e => e.Revision)); + var latest = extras.Last (); + var entry = new JObject { + new JProperty ("desc", latest.Element.ReqAttr ("description")), + new JProperty ("sdkPackage", new JObject { + new JProperty ("id", path), + new JProperty ("version", "[" + version + "]"), + new JProperty ("recommendedId", latest.Element.ReqAttr ("path")), + new JProperty ("recommendedVersion", latest.Revision), + }), + new JProperty ("optional", "true"), + }; + yield return entry; + } +} + +IEnumerable CreateSystemImagePackageEntries (XDocument doc) +{ + // path="system-images;android-21;default;armeabi-v7a" + var images = from image in GetSupportedElements (doc, "system-image") + let path = image.ReqAttr ("path") + let parts = path.Split (';') + where parts.Length > 3 + let targetApi = parts [1] + let apiImpl = parts [2] // google_apis or default + let targetAbi = parts [3] + select new { + Element = image, + Path = path, + TargetApi = targetApi, + ApiImpl = apiImpl, + TargetAbi = targetAbi, + }; + var maxTarget = images.Select (image => image.TargetApi).OrderBy (v => v).Last (); + var maxImages = images.Where (image => image.TargetApi == maxTarget); + + var x64 = maxImages.Where (image => image.TargetAbi == "x86_64").FirstOrDefault (); + var arm64 = maxImages.Where (image => image.TargetAbi == "arm64-v8a").FirstOrDefault (); + if (x64 == null && arm64 == null) { + yield break; + } + + var id = new JObject (); + if (x64 != null) { + id.Add (new JProperty ("win-x64", x64.Path)); + id.Add (new JProperty ("mac-x64", x64.Path)); + id.Add (new JProperty ("linux-x64", x64.Path)); + } + if (arm64 != null) { + id.Add (new JProperty ("mac-arm64", arm64.Path)); + id.Add (new JProperty ("linux-arm64", arm64.Path)); + } + + var entry = new JObject { + new JProperty ("desc", maxImages.First ().Element.ReqAttr ("description")), + new JProperty ("sdkPackage", new JObject { + new JProperty ("id", id), + }), + new JProperty ("optional", "true"), + }; + yield return entry; +} + +JArray CreatePackagesArray (XDocument doc) +{ + var packages = new JArray (); + var names = doc.Root!.Elements () + .Select (e => e.Name.LocalName) + .Distinct () + .OrderBy (e => e); + foreach (var name in names) { + if (PackageCreators.TryGetValue (name, out var creator)) { + foreach (var e in creator (doc)) { + packages.Add (e); + } + continue; + } + var items = GetSupportedElements (doc, name) + .OrderBy (e => e.ReqAttr ("path")); + if (!items.Any ()) { + continue; + } + var version = string.Join (",", items.Select (e => e.ReqAttr ("revision"))); + var latest = items.Last (); + + var entry = new JObject { + new JProperty ("desc", latest.ReqAttr ("description")), + new JProperty ("sdkPackage", new JObject { + new JProperty ("id", GetEntryId (latest)), + new JProperty ("version", "[" + version + "]"), + new JProperty ("recommendedId", latest.ReqAttr ("path")), + new JProperty ("recommendedVersion", latest.ReqAttr ("revision")), + }), + new JProperty ("optional", (!RequiredPackages.Contains (name)).ToString ().ToLowerInvariant ()), + }; + + packages.Add (entry); + } + return packages; +} + +string GetEntryId (XElement entry) +{ + var path = entry.ReqAttr ("path"); + var semic = path.LastIndexOf (';'); + if (semic < 0) { + return path; + } + var hyphen = path.LastIndexOf ('-'); + if (hyphen < 0) { + return path.Substring (0, semic+1) + "*"; + } + return path.Substring (0, Math.Max (hyphen, semic)+1) + "*"; +} + +static class Extensions +{ + public static string ReqAttr (this XElement e, string attribute) + { + var v = (string?) e.Attribute (attribute); + if (v == null) { + throw new InvalidOperationException ($"Missing required attribute `{attribute}` in: `{e}"); + } + return v; + } + + public static IEnumerable<(XElement Element, string Revision)> OrderByRevision (this IEnumerable elements) + { + return from e in elements + let revision = e.ReqAttr ("revision") + let version = new Version (revision.Contains (".") ? revision : revision + ".0") + orderby version + select (e, revision); + } +} diff --git a/tools/workload-dependencies/workload-dependencies.csproj b/tools/workload-dependencies/workload-dependencies.csproj new file mode 100644 index 00000000000..3f9921bddd8 --- /dev/null +++ b/tools/workload-dependencies/workload-dependencies.csproj @@ -0,0 +1,15 @@ + + + + Exe + net9.0 + release_json + enable + enable + + + + + + + From 52182a0e269db857b11fbece41220c77e7aa578f Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 13 Dec 2024 11:46:13 -0500 Subject: [PATCH 2/6] Address feedback Context: https://github.com/dotnet/android/pull/9613#issuecomment-2539799666 A lot of the previous output was nonsensical, especially around `version`s, in large part because I was trying to associate the `//*/@revision` attribute in the Feed to a version. This sometimes works, e.g. for build-tools and platform-tools, but would fail horribly for things like ``, resulting in JSON fragments such as: { "desc": "Android SDK Platform 28", "sdkPackage": { "id": "platforms;android-*", "version": "[1,1,1,2,2,2,2,3,3,3,3,3,3,5,6]", "recommendedId": "platforms;android-28", "recommendedVersion": "6" }, "optional": "false" }, Make to fundamental architectural changes: 1. Instead of trying to emit JSON for *everything* in the feed, only emit JSON for a minimal subset of known required+optional pieces, such as platform-tools (required) and the emulator and system images (optional). 2. Drop the idea of "version", "recommendedId", and "recommendedVersion". This results in a much smaller and more sensible: { "microsoft.net.sdk.android": { "workload": { "alias": [ "android" ], "version": "35.0.100" }, "jdk": { "version": "[17.0,18.0)", "recommendedVersion": "17.0.12" }, "androidsdk": { "packages": [ { "desc": "Android SDK Build-Tools 35", "sdkPackage": { "id": "build-tools;35.0.0" }, "optional": "false" }, { "desc": "Android SDK Command-line Tools", "sdkPackage": { "id": "cmdline-tools;13.0" }, "optional": "false" }, { "desc": "Android Emulator", "sdkPackage": { "id": "emulator" }, "optional": "true" }, { "desc": "NDK (Side by side) 27.1.12297006", "sdkPackage": { "id": "ndk;27.1.12297006" }, "optional": "true" }, { "desc": "Android SDK Platform 35", "sdkPackage": { "id": "platforms;android-35" }, "optional": "false" }, { "desc": "Android SDK Platform Baklava (Preview)", "sdkPackage": { "id": "platforms;android-Baklava" }, "optional": "true" }, { "desc": "Android SDK Platform-Tools", "sdkPackage": { "id": "platform-tools" }, "optional": "false" }, { "desc": "Google APIs ARM 64 v8a System Image", "sdkPackage": { "id": { "win-x64": "system-images;android-35;google_apis;x86_64", "mac-x64": "system-images;android-35;google_apis;x86_64", "linux-x64": "system-images;android-35;google_apis;x86_64", "mac-arm64": "system-images;android-35;google_apis;arm64-v8a", "linux-arm64": "system-images;android-35;google_apis;arm64-v8a" } }, "optional": "true" } ] } } } --- .../Microsoft.NET.Sdk.Android.proj | 16 +- tools/workload-dependencies/Program.cs | 255 ++++++++++-------- 2 files changed, 152 insertions(+), 119 deletions(-) diff --git a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj index d978402ee20..f9716278263 100644 --- a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj +++ b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj @@ -48,10 +48,22 @@ about the various Microsoft.Android workloads. <_Feed Condition=" Exists($(_AndroidPlatformSupportFeed)) ">$(_AndroidPlatformSupportFeed) <_Feed Condition=" '$(_Feed)' == '' ">https://aka.ms/AndroidManifestFeed/d17-12 <_Project>$(MSBuildThisFileDirectory)/../../tools/workload-dependencies/workload-dependencies.csproj - $(OutputPath)workload-manifest\workload-dependencies.json + $(OutputPath)workload-manifest\WorkloadDependencies.json + + <_WorkloadDeps Include="--project "$(_Project)"" /> + <_WorkloadDeps Include="--" /> + <_WorkloadDeps Include=""--feed=$(_Feed)"" /> + <_WorkloadDeps Include="-o "$(WorkloadDependenciesPath)"" /> + <_WorkloadDeps Include="--build-tools-version=$(XABuildToolsFolder)" /> + <_WorkloadDeps Include="--cmdline-tools-version=$(CommandLineToolsFolder)" /> + <_WorkloadDeps Include="--jdk-version=$(JavaSdkVersion)" /> + <_WorkloadDeps Include="--platform-version=$(AndroidLatestStableApiLevel)" /> + <_WorkloadDeps Include="--preview-platform-version=Baklava" /> + <_WorkloadDeps Include="--workload-version=$(WorkloadVersion)" /> + - + <_PackageFiles Include="$(WorkloadManifestJsonPath)" PackagePath="data" /> diff --git a/tools/workload-dependencies/Program.cs b/tools/workload-dependencies/Program.cs index 575e1110f1c..8e4a17a9486 100644 --- a/tools/workload-dependencies/Program.cs +++ b/tools/workload-dependencies/Program.cs @@ -5,35 +5,52 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -const string AppName = "release-json"; - -var RequiredPackages = new HashSet { - "platform-tools", - "cmdline-tools", - "build-tool", - "platform", -}; - -var help = false; -var feed = (string?) null; -var output = (string?) null; -int verbosity = 0; -var workloadVersion = (string?) null; +const string AppName = "workload-dependencies"; + +var help = false; +var feed = (string?) null; +var output = (string?) null; +int Verbosity = 0; +var CmdlineToolsVersion = (string?) null; +var BuildToolsVersion = (string?) null; +var JdkVersion = (string?) null; +var NdkVersion = (string?) null; +var PreviewPlatformVersion = (string?) null; +var PlatformVersion = (string?) null; +var WorkloadVersion = (string?) null; var options = new OptionSet { "Generate `release.json` from Feed XML file.", { "i|feed=", - "The {PATH} to the Feed XML file.", + "The {PATH} to the Feed XML file to process.", v => feed = v }, { "o|output=", - "The {PATH} to the output release.json file.", + "The {FILE_PATH} for the JSON output.\nDefault is stdout.", v => output = v }, + { "build-tools-version=", + "The Android SDK Build-Tools {VERSION} dotnet/android is built against.", + v => BuildToolsVersion = v }, + { "cmdline-tools-version=", + "The Android SDK cmdline-tools {VERSION} dotnet/android is built against.", + v => CmdlineToolsVersion = v }, + { "jdk-version=", + "The JDK {VERSION} dotnet/android is built against.", + v => JdkVersion = v }, + { "ndk-version=", + "The Android NDK {VERSION} dotnet/android is built against.", + v => NdkVersion = v }, + { "platform-version=", + "The stable Android SDK Platform {VERSION} dotnet/android binds.", + v => PlatformVersion = v }, + { "preview-platform-version=", + "The preview Android SDK Platform {VERSION} dotnet/android binds.", + v => PreviewPlatformVersion = v }, { "workload-version=", - "The {VERSION} of the workload to generate.", - v => workloadVersion = v }, + "The {VERSION} of the dotnet/android workload.", + v => WorkloadVersion = v }, { "v|verbose:", - "Set internal message verbosity", - (int? v) => verbosity = v.HasValue ? v.Value : verbosity + 1 }, + "Set internal message Verbosity", + (int? v) => Verbosity = v.HasValue ? v.Value : Verbosity + 1 }, { "h|help", "Show this help message and exit", v => help = v != null }, @@ -61,25 +78,28 @@ } catch (OptionException e) { Console.Error.WriteLine ($"{AppName}: {e.Message}"); - if (verbosity > 0) { + if (Verbosity > 0) { Console.Error.WriteLine (e.ToString ()); } return; } catch (System.Xml.XmlException e) { Console.Error.WriteLine ($"{AppName}: invalid `--feed=PATH` value. {e.Message}"); - if (verbosity > 0) { + if (Verbosity > 0) { Console.Error.WriteLine (e.ToString ()); } return; } var PackageCreators = new Dictionary>> { - ["addon"] = CreateAddonPackageEntries, - ["extra"] = CreateExtraPackageEntries, - ["jdk"] = doc => Array.Empty (), - ["licenses"] = doc => Array.Empty (), + ["build-tool"] = doc => CreatePackageEntries (doc, "build-tool", BuildToolsVersion), + ["emulator"] = doc => CreatePackageEntries (doc, "emulator", null, optional: true), + ["cmdline-tools"] = doc => CreatePackageEntries (doc, "cmdline-tools", CmdlineToolsVersion), + ["ndk"] = doc => CreatePackageEntries (doc, "ndk", NdkVersion, optional: true), + ["platform-tools"] = doc => CreatePackageEntries (doc, "platform-tools", null), + ["platform"] = CreatePlatformPackageEntries, ["system-image"] = CreateSystemImagePackageEntries, + // ndk }; var release = new JObject { @@ -127,16 +147,19 @@ JProperty CreateWorkloadProperty (XDocument doc) { var contents = new JObject ( new JProperty ("alias", new JArray ("android"))); - if (!string.IsNullOrEmpty (workloadVersion)) - contents.Add (new JProperty ("version", workloadVersion)); + if (!string.IsNullOrEmpty (WorkloadVersion)) + contents.Add (new JProperty ("version", WorkloadVersion)); return new JProperty ("workload", contents); } JProperty CreateJdkProperty (XDocument doc) { - var latestRevision = GetLatestRevision (doc, "jdk"); + var v = new Version (JdkVersion ?? "17.0"); + var start = new Version (v.Major, v.Minor); + var end = new Version (v.Major+1, 0); + var latestRevision = JdkVersion ?? GetLatestRevision (doc, "jdk"); var contents = new JObject ( - new JProperty ("version", "[17.0,18.0)")); + new JProperty ("version", $"[{start},{end})")); if (!string.IsNullOrEmpty (latestRevision)) contents.Add (new JProperty ("recommendedVersion", latestRevision)); return new JProperty ("jdk", contents); @@ -150,7 +173,8 @@ IEnumerable GetSupportedElements (XDocument doc, string element) return doc.Root.Elements (element) .Where (e => string.Equals ("False", e.ReqAttr ("obsolete"), StringComparison.OrdinalIgnoreCase) && - string.Equals ("False", e.ReqAttr ("preview"), StringComparison.OrdinalIgnoreCase)); + string.Equals ("False", e.ReqAttr ("preview"), StringComparison.OrdinalIgnoreCase)) + ; } IEnumerable<(XElement Element, string Revision)> GetByRevisions (XDocument doc, string element) @@ -166,54 +190,84 @@ IEnumerable GetSupportedElements (XDocument doc, string element) .Revision; } -IEnumerable CreateAddonPackageEntries (XDocument doc) +IEnumerable CreatePackageEntries (XDocument doc, string element, string? revision, bool optional = false) { - var allAddons = GetSupportedElements (doc, "addon").ToList () - .OrderBy (e => e.ReqAttr ("path")); - var paths = allAddons - .Select (e => GetEntryId (e)) - .Distinct (); - foreach (var path in paths) { - var addons = allAddons - .Where (e => GetEntryId (e) == path); - var version = string.Join (",", addons.Select (e => e.ReqAttr ("revision"))); - var latest = addons.Last (); - var entry = new JObject { - new JProperty ("desc", latest.ReqAttr ("description")), - new JProperty ("sdkPackage", new JObject { - new JProperty ("id", path), - new JProperty ("version", "[" + version + "]"), - new JProperty ("recommendedId", latest.ReqAttr ("path")), - new JProperty ("recommendedVersion", latest.ReqAttr ("revision")), - }), - new JProperty ("optional", "true"), - }; - yield return entry; + var item = GetElementRevision (doc, element, revision); + if (item == null) { + yield break; } + var entry = new JObject { + new JProperty ("desc", item.ReqAttr ("description")), + new JProperty ("sdkPackage", new JObject { + new JProperty ("id", item.ReqAttr ("path")), + }), + new JProperty ("optional", optional.ToString ().ToLowerInvariant ()), + }; + yield return entry; } -IEnumerable CreateExtraPackageEntries (XDocument doc) +XElement? GetElementRevision (XDocument doc, string element, string? revision) { - var allExtras = GetByRevisions (doc, "extra").ToList (); - var paths = allExtras - .Select (e => e.Element.ReqAttr ("path")) - .Distinct (); - foreach (var path in paths) { - var extras = allExtras - .Where (e => e.Element.ReqAttr ("path") == path); - var version = string.Join (",", extras.Select (e => e.Revision)); - var latest = extras.Last (); - var entry = new JObject { - new JProperty ("desc", latest.Element.ReqAttr ("description")), + Version? reqVersion = revision != null ? new Version (revision) : null;; + Version? maxVersion = null; + XElement? entry = null; + foreach (var e in GetSupportedElements (doc, element)) { + var r = e.ReqAttr ("revision"); + var rv = new Version (r); + if (rv == reqVersion) { + return e; + } + if (rv > maxVersion) { + maxVersion = rv; + entry = e; + } + } + return entry; +} + +IEnumerable CreatePlatformPackageEntries (XDocument doc) +{ + string? reqVersion = PlatformVersion != null + ? $"platforms;android-{PlatformVersion}" + : null; + string? maxVersion = null; + XElement? entry = null; + foreach (var e in GetSupportedElements (doc, "platform")) { + var path = e.ReqAttr ("path"); + if (path == reqVersion) { + entry = e; + break; + } + if (string.Compare (path, maxVersion) > 0) { + maxVersion = path; + entry = e; + } + } + if (entry == null) { + yield break; + } + var platform = new JObject { + new JProperty ("desc", entry.ReqAttr ("description")), + new JProperty ("sdkPackage", new JObject { + new JProperty ("id", entry.ReqAttr ("path")), + }), + new JProperty ("optional", "false"), + }; + yield return platform; + + string? previewPath = PreviewPlatformVersion != null + ? $"platforms;android-{PreviewPlatformVersion}" + : null; + XElement? previewEntry = doc.Elements ("platform") + .FirstOrDefault (e => e.ReqAttr ("path") == previewPath); + if (PreviewPlatformVersion != null) { + yield return new JObject { + new JProperty ("desc", previewEntry?.ReqAttr ("description") ?? $"Android SDK Platform {PreviewPlatformVersion} (Preview)"), new JProperty ("sdkPackage", new JObject { - new JProperty ("id", path), - new JProperty ("version", "[" + version + "]"), - new JProperty ("recommendedId", latest.Element.ReqAttr ("path")), - new JProperty ("recommendedVersion", latest.Revision), + new JProperty ("id", previewPath), }), - new JProperty ("optional", "true"), + new JProperty ("optional", "true"), }; - yield return entry; } } @@ -225,8 +279,9 @@ IEnumerable CreateSystemImagePackageEntries (XDocument doc) let parts = path.Split (';') where parts.Length > 3 let targetApi = parts [1] - let apiImpl = parts [2] // google_apis or default + let apiImpl = parts [2] // google_apis or default let targetAbi = parts [3] + where apiImpl == "google_apis" // prefer google_apis select new { Element = image, Path = path, @@ -245,21 +300,21 @@ where parts.Length > 3 var id = new JObject (); if (x64 != null) { - id.Add (new JProperty ("win-x64", x64.Path)); - id.Add (new JProperty ("mac-x64", x64.Path)); - id.Add (new JProperty ("linux-x64", x64.Path)); + id.Add (new JProperty ("win-x64", x64.Path)); + id.Add (new JProperty ("mac-x64", x64.Path)); + id.Add (new JProperty ("linux-x64", x64.Path)); } if (arm64 != null) { - id.Add (new JProperty ("mac-arm64", arm64.Path)); - id.Add (new JProperty ("linux-arm64", arm64.Path)); + id.Add (new JProperty ("mac-arm64", arm64.Path)); + id.Add (new JProperty ("linux-arm64", arm64.Path)); } var entry = new JObject { - new JProperty ("desc", maxImages.First ().Element.ReqAttr ("description")), - new JProperty ("sdkPackage", new JObject { + new JProperty ("desc", maxImages.First ().Element.ReqAttr ("description")), + new JProperty ("sdkPackage", new JObject { new JProperty ("id", id), }), - new JProperty ("optional", "true"), + new JProperty ("optional", "true"), }; yield return entry; } @@ -272,50 +327,16 @@ JArray CreatePackagesArray (XDocument doc) .Distinct () .OrderBy (e => e); foreach (var name in names) { - if (PackageCreators.TryGetValue (name, out var creator)) { - foreach (var e in creator (doc)) { - packages.Add (e); - } + if (!PackageCreators.TryGetValue (name, out var creator)) { continue; } - var items = GetSupportedElements (doc, name) - .OrderBy (e => e.ReqAttr ("path")); - if (!items.Any ()) { - continue; + foreach (var e in creator (doc)) { + packages.Add (e); } - var version = string.Join (",", items.Select (e => e.ReqAttr ("revision"))); - var latest = items.Last (); - - var entry = new JObject { - new JProperty ("desc", latest.ReqAttr ("description")), - new JProperty ("sdkPackage", new JObject { - new JProperty ("id", GetEntryId (latest)), - new JProperty ("version", "[" + version + "]"), - new JProperty ("recommendedId", latest.ReqAttr ("path")), - new JProperty ("recommendedVersion", latest.ReqAttr ("revision")), - }), - new JProperty ("optional", (!RequiredPackages.Contains (name)).ToString ().ToLowerInvariant ()), - }; - - packages.Add (entry); } return packages; } -string GetEntryId (XElement entry) -{ - var path = entry.ReqAttr ("path"); - var semic = path.LastIndexOf (';'); - if (semic < 0) { - return path; - } - var hyphen = path.LastIndexOf ('-'); - if (hyphen < 0) { - return path.Substring (0, semic+1) + "*"; - } - return path.Substring (0, Math.Max (hyphen, semic)+1) + "*"; -} - static class Extensions { public static string ReqAttr (this XElement e, string attribute) From 9504691f32203ed87da51c5a90f9743987a0e3aa Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 13 Dec 2024 14:35:14 -0500 Subject: [PATCH 3/6] Emit preview platform only when we have a preview. Provide NDK version. --- build-tools/create-packs/Microsoft.NET.Sdk.Android.proj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj index f9716278263..cd6f2c2f52d 100644 --- a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj +++ b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj @@ -58,8 +58,12 @@ about the various Microsoft.Android workloads. <_WorkloadDeps Include="--build-tools-version=$(XABuildToolsFolder)" /> <_WorkloadDeps Include="--cmdline-tools-version=$(CommandLineToolsFolder)" /> <_WorkloadDeps Include="--jdk-version=$(JavaSdkVersion)" /> + <_WorkloadDeps Include="--ndk-version=$(AndroidNdkPkgRevision)" /> <_WorkloadDeps Include="--platform-version=$(AndroidLatestStableApiLevel)" /> - <_WorkloadDeps Include="--preview-platform-version=Baklava" /> + <_WorkloadDeps + Condition=" '$(AndroidLatestUnstablePlatformId)' != '$(AndroidLatestStablePlatformId)' " + Include="--preview-platform-version=$(AndroidLatestUnstablePlatformId)" + /> <_WorkloadDeps Include="--workload-version=$(WorkloadVersion)" /> From 1510e87be645360f6c559e454c4562841bc30327 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 17 Dec 2024 15:04:17 -0500 Subject: [PATCH 4/6] Prefer versions from android-platform-support Context: 51151d727a0438dd049ad2678f9039d8f255d7b2 Commit 51151d72 laid out a conundrum: dotnet/android builds against one set of versioned dependencies, but we want the "Xamarin Manifest" to *actually* dictate the preferred package versions, as this makes it easier to keep versions in sync with the VS installer/etc. The problem is that commits prior to this point ignored the `Xamarin.Installer.Common.props` described in 51151d72. Additionally, many of the MSBuild properties are (1) "conditional" -- only setting a value if not overridden -- and (2) have the same names as the properties within `Xamarin.Installer.Common.props`. Square this circle by doing two things: 1. Add `tools/workload-dependencies/WorkloadDependencies.proj` alongside `tools/workload-dependencies/Directory.Build.props`, which allows for an "isolated" environment, one in which *only* `Xamarin.Installer.Common.props` and `Xamarin.Android.Common.props` are imported. This allows us to cleanly ensure that `Xamarin.Installer.Common.props` controls things. 2. Update `Microsoft.NET.Sdk.Android.proj` to use the `` task to invoke `WorkloadDependencies.proj`, providing all MSBuild properties required for things to work. This should ensure that package versions are consistent. Additionally, update `Program.cs` so that the `platform-tools` package contains a `requestedRevision` property. The `platform-tools` package is *unversioned*, so this is the only way to get some semblance of versioning involved. --- .../Microsoft.NET.Sdk.Android.proj | 35 +++----- .../Directory.Build.props | 8 ++ tools/workload-dependencies/Program.cs | 24 ++++-- .../WorkloadDependencies.proj | 81 +++++++++++++++++++ 4 files changed, 120 insertions(+), 28 deletions(-) create mode 100644 tools/workload-dependencies/Directory.Build.props create mode 100644 tools/workload-dependencies/WorkloadDependencies.proj diff --git a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj index cd6f2c2f52d..710222cc133 100644 --- a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj +++ b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj @@ -26,6 +26,7 @@ about the various Microsoft.Android workloads. + $(OutputPath)workload-manifest\WorkloadDependencies.json $(OutputPath)workload-manifest\WorkloadManifest.json $(OutputPath)workload-manifest\WorkloadManifest.targets $(AndroidPackVersionLong) @@ -43,31 +44,21 @@ about the various Microsoft.Android workloads. Replacements="@NET_PREVIOUS_VERSION@=$(AndroidNetPreviousVersion)"> - - <_AndroidPlatformSupportFeed>$(MSBuildThisFileDirectory)/../../external/android-platform-support/Feeds/AndroidManifestFeed_d17.12.xml - <_Feed Condition=" Exists($(_AndroidPlatformSupportFeed)) ">$(_AndroidPlatformSupportFeed) - <_Feed Condition=" '$(_Feed)' == '' ">https://aka.ms/AndroidManifestFeed/d17-12 - <_Project>$(MSBuildThisFileDirectory)/../../tools/workload-dependencies/workload-dependencies.csproj - $(OutputPath)workload-manifest\WorkloadDependencies.json - - <_WorkloadDeps Include="--project "$(_Project)"" /> - <_WorkloadDeps Include="--" /> - <_WorkloadDeps Include=""--feed=$(_Feed)"" /> - <_WorkloadDeps Include="-o "$(WorkloadDependenciesPath)"" /> - <_WorkloadDeps Include="--build-tools-version=$(XABuildToolsFolder)" /> - <_WorkloadDeps Include="--cmdline-tools-version=$(CommandLineToolsFolder)" /> - <_WorkloadDeps Include="--jdk-version=$(JavaSdkVersion)" /> - <_WorkloadDeps Include="--ndk-version=$(AndroidNdkPkgRevision)" /> - <_WorkloadDeps Include="--platform-version=$(AndroidLatestStableApiLevel)" /> - <_WorkloadDeps - Condition=" '$(AndroidLatestUnstablePlatformId)' != '$(AndroidLatestStablePlatformId)' " - Include="--preview-platform-version=$(AndroidLatestUnstablePlatformId)" - /> - <_WorkloadDeps Include="--workload-version=$(WorkloadVersion)" /> + <_WorkloadDepProp Include="AndroidLatestStablePlatformId=$(AndroidLatestStablePlatformId)" /> + <_WorkloadDepProp Include="AndroidLatestUnstablePlatformId=$(AndroidLatestUnstablePlatformId)" /> + <_WorkloadDepProp Include="MicrosoftAndroidSdkOutDir=$(MicrosoftAndroidSdkOutDir)" /> + <_WorkloadDepProp Include="MonoOptionsVersion=$(MonoOptionsVersion)" /> + <_WorkloadDepProp Include="NewtonsoftJsonPackageVersion=$(NewtonsoftJsonPackageVersion)" /> + <_WorkloadDepProp Include="WorkloadDependenciesPath=$(WorkloadDependenciesPath)" /> + <_WorkloadDepProp Include="WorkloadVersion=$(WorkloadVersion)" /> - + <_PackageFiles Include="$(WorkloadManifestJsonPath)" PackagePath="data" /> diff --git a/tools/workload-dependencies/Directory.Build.props b/tools/workload-dependencies/Directory.Build.props new file mode 100644 index 00000000000..f779f1ff252 --- /dev/null +++ b/tools/workload-dependencies/Directory.Build.props @@ -0,0 +1,8 @@ + + + diff --git a/tools/workload-dependencies/Program.cs b/tools/workload-dependencies/Program.cs index 8e4a17a9486..d5e8422b26a 100644 --- a/tools/workload-dependencies/Program.cs +++ b/tools/workload-dependencies/Program.cs @@ -15,8 +15,9 @@ var BuildToolsVersion = (string?) null; var JdkVersion = (string?) null; var NdkVersion = (string?) null; -var PreviewPlatformVersion = (string?) null; +var PlatformToolsVersion = (string?) null; var PlatformVersion = (string?) null; +var PreviewPlatformVersion = (string?) null; var WorkloadVersion = (string?) null; var options = new OptionSet { @@ -39,6 +40,9 @@ { "ndk-version=", "The Android NDK {VERSION} dotnet/android is built against.", v => NdkVersion = v }, + { "platform-tools-version=", + "The Android SDK platform-tools version dotnet/android is built against.", + v => PlatformToolsVersion = v }, { "platform-version=", "The stable Android SDK Platform {VERSION} dotnet/android binds.", v => PlatformVersion = v }, @@ -96,7 +100,7 @@ ["emulator"] = doc => CreatePackageEntries (doc, "emulator", null, optional: true), ["cmdline-tools"] = doc => CreatePackageEntries (doc, "cmdline-tools", CmdlineToolsVersion), ["ndk"] = doc => CreatePackageEntries (doc, "ndk", NdkVersion, optional: true), - ["platform-tools"] = doc => CreatePackageEntries (doc, "platform-tools", null), + ["platform-tools"] = doc => CreatePackageEntries (doc, "platform-tools", PlatformToolsVersion), ["platform"] = CreatePlatformPackageEntries, ["system-image"] = CreateSystemImagePackageEntries, // ndk @@ -196,11 +200,19 @@ IEnumerable CreatePackageEntries (XDocument doc, string element, string if (item == null) { yield break; } + var path = item.ReqAttr ("path"); + var reqRev = item.ReqAttr ("revision"); + var sdkPackage = new JObject { + new JProperty ("id", path), + }; + + // special-case platform-tools, which doesn't have a revision + if (!path.Contains (reqRev)) { + sdkPackage.Add (new JProperty ("requestedRevision", reqRev)); + } var entry = new JObject { new JProperty ("desc", item.ReqAttr ("description")), - new JProperty ("sdkPackage", new JObject { - new JProperty ("id", item.ReqAttr ("path")), - }), + new JProperty ("sdkPackage", sdkPackage), new JProperty ("optional", optional.ToString ().ToLowerInvariant ()), }; yield return entry; @@ -228,7 +240,7 @@ IEnumerable CreatePackageEntries (XDocument doc, string element, string IEnumerable CreatePlatformPackageEntries (XDocument doc) { string? reqVersion = PlatformVersion != null - ? $"platforms;android-{PlatformVersion}" + ? $"platforms;{PlatformVersion}" : null; string? maxVersion = null; XElement? entry = null; diff --git a/tools/workload-dependencies/WorkloadDependencies.proj b/tools/workload-dependencies/WorkloadDependencies.proj new file mode 100644 index 00000000000..78de90a4d9e --- /dev/null +++ b/tools/workload-dependencies/WorkloadDependencies.proj @@ -0,0 +1,81 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + + + <_AndroidPlatformSupportFeed>$(MSBuildThisFileDirectory)/../../external/android-platform-support/Feeds/AndroidManifestFeed_d17.12.xml + <_Feed Condition=" Exists($(_AndroidPlatformSupportFeed)) ">$(_AndroidPlatformSupportFeed) + <_Feed Condition=" '$(_Feed)' == '' ">https://aka.ms/AndroidManifestFeed/d17-12 + <_Project>$(MSBuildThisFileDirectory)workload-dependencies.csproj + $(OutputPath)workload-manifest\WorkloadDependencies.json + + + + <_WorkloadDeps Include="--project "$(_Project)"" /> + <_WorkloadDeps Include="-p:MonoOptionsVersion=$(MonoOptionsVersion)" /> + <_WorkloadDeps Include="-p:NewtonsoftJsonPackageVersion=$(NewtonsoftJsonPackageVersion)" /> + <_WorkloadDeps Include="--" /> + <_WorkloadDeps Include=""--feed=$(_Feed)"" /> + <_WorkloadDeps Include="-o "$(WorkloadDependenciesPath)"" /> + <_WorkloadDeps Include="--build-tools-version=$(AndroidSdkBuildToolsVersion)" /> + <_WorkloadDeps Include="--cmdline-tools-version=$(AndroidCommandLineToolsVersion)" /> + <_WorkloadDeps Include="--jdk-version=$(JavaSdkVersion)" /> + <_WorkloadDeps Include="--ndk-version=$(AndroidNdkVersion)" /> + <_WorkloadDeps Include="--platform-tools-version=$(AndroidSdkPlatformToolsVersion)" /> + <_WorkloadDeps Include="--platform-version=$(AndroidSdkPlatformVersion)" /> + <_WorkloadDeps + Condition=" '$(AndroidLatestUnstablePlatformId)' != '$(AndroidLatestStablePlatformId)' " + Include="--preview-platform-version=$(AndroidLatestUnstablePlatformId)" + /> + <_WorkloadDeps Include="--workload-version=$(WorkloadVersion)" /> + + + + + + + From 58099a6489fae24d98a8e44e7f61ebb3c9ea09db Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 17 Dec 2024 16:33:20 -0500 Subject: [PATCH 5/6] "recommendedVersion", not "requestedVersion". --- tools/workload-dependencies/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/workload-dependencies/Program.cs b/tools/workload-dependencies/Program.cs index d5e8422b26a..c61ab3b1d39 100644 --- a/tools/workload-dependencies/Program.cs +++ b/tools/workload-dependencies/Program.cs @@ -208,7 +208,7 @@ IEnumerable CreatePackageEntries (XDocument doc, string element, string // special-case platform-tools, which doesn't have a revision if (!path.Contains (reqRev)) { - sdkPackage.Add (new JProperty ("requestedRevision", reqRev)); + sdkPackage.Add (new JProperty ("recommendedVersion", reqRev)); } var entry = new JObject { new JProperty ("desc", item.ReqAttr ("description")), From cdad1e99030bb041a7d7a987d85937d4541b2e52 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 17 Dec 2024 22:02:14 -0500 Subject: [PATCH 6/6] Address feedback --- build-tools/create-packs/Microsoft.NET.Sdk.Android.proj | 1 + tools/workload-dependencies/WorkloadDependencies.proj | 4 ++++ tools/workload-dependencies/workload-dependencies.csproj | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj index 710222cc133..dc761f56110 100644 --- a/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj +++ b/build-tools/create-packs/Microsoft.NET.Sdk.Android.proj @@ -47,6 +47,7 @@ about the various Microsoft.Android workloads. <_WorkloadDepProp Include="AndroidLatestStablePlatformId=$(AndroidLatestStablePlatformId)" /> <_WorkloadDepProp Include="AndroidLatestUnstablePlatformId=$(AndroidLatestUnstablePlatformId)" /> + <_WorkloadDepProp Include="DotNetStableTargetFramework=$(DotNetStableTargetFramework)" /> <_WorkloadDepProp Include="MicrosoftAndroidSdkOutDir=$(MicrosoftAndroidSdkOutDir)" /> <_WorkloadDepProp Include="MonoOptionsVersion=$(MonoOptionsVersion)" /> <_WorkloadDepProp Include="NewtonsoftJsonPackageVersion=$(NewtonsoftJsonPackageVersion)" /> diff --git a/tools/workload-dependencies/WorkloadDependencies.proj b/tools/workload-dependencies/WorkloadDependencies.proj index 78de90a4d9e..e8831e28a87 100644 --- a/tools/workload-dependencies/WorkloadDependencies.proj +++ b/tools/workload-dependencies/WorkloadDependencies.proj @@ -37,6 +37,10 @@ Condition=" '$(AndroidLatestUnstablePlatformId)' == '' " Text="AndroidLatestUnstablePlatformId property must be set." /> + Exe - net9.0 + $(DotNetStableTargetFramework) release_json enable enable