Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Android.Build.Tasks;
using Xamarin.Android.Tasks;

namespace Xamarin.Android.Tasks
namespace Microsoft.Android.Tasks
{
[MSBuildMultiThreadableTask]
public class GetAndroidDefineConstants : MultithreadedAndroidTask
public partial class GetAndroidDefineConstants : MultithreadedAndroidTask
{
public override string TaskPrefix => "GAD";

Expand All @@ -23,12 +24,15 @@ public class GetAndroidDefineConstants : MultithreadedAndroidTask
[Output]
public ITaskItem[]? AndroidDefineConstants { get; set; }

[GeneratedRegex ("[^A-Za-z0-9]")]
private static partial Regex NonAlphanumericRegex { get; }

public override bool RunTask ()
{
var constants = new List<ITaskItem> ();

if (!ProductVersion.IsNullOrEmpty ()) {
var version = Regex.Replace (ProductVersion, "[^A-Za-z0-9]", "_");
var version = NonAlphanumericRegex.Replace (ProductVersion, "_");
constants.Add (new TaskItem ($"__XAMARIN_ANDROID_{version}__"));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using NUnit.Framework;
using Microsoft.Android.Tasks;

namespace Xamarin.Android.Build.Tests
{
[TestFixture]
public class GetAndroidDefineConstantsTests : BaseTest
{
[TestCase ("36", null, 36, "")]
[TestCase ("36.1", null, 36, "__ANDROID_36_1__")]
[TestCase ("38.2", "11.0-rc+test", 38, "__ANDROID_36_1__;__ANDROID_37_1__;__ANDROID_37_2__;__ANDROID_37_3__;__ANDROID_37_4__;__ANDROID_38_1__;__ANDROID_38_2__")]
public void Constants (string apiLevel, string? productVersion, int major, string minorConstants)
{
var task = new GetAndroidDefineConstants {
AndroidApiLevel = apiLevel,
ProductVersion = productVersion,
};
Assert.IsTrue (task.Execute ());
var constants = task.AndroidDefineConstants ?? throw new InvalidOperationException ("No constants returned.");
var expected = new List<string> ();
if (productVersion != null)
expected.Add ("__XAMARIN_ANDROID_11_0_rc_test__");
expected.AddRange (["__MOBILE__", "__ANDROID__"]);
expected.AddRange (Enumerable.Range (1, major).Select (i => $"__ANDROID_{i}__"));
expected.AddRange (minorConstants.Split (';', StringSplitOptions.RemoveEmptyEntries));
CollectionAssert.AreEqual (expected, constants.Select (i => i.ItemSpec));
}

[TestCase ("")]
[TestCase ("invalid")]
public void InvalidApiLevel (string apiLevel)
{
var errors = new List<BuildErrorEventArgs> ();
var task = new GetAndroidDefineConstants {
AndroidApiLevel = apiLevel,
BuildEngine = new MockBuildEngine (TestContext.Out, errors: errors),
};
Assert.IsFalse (task.Execute ());
Assert.IsNull (task.AndroidDefineConstants);
Assert.IsEmpty (errors);
}

[TestCase ("GetAndroidDefineConstants")]
[TestCase ("Microsoft.Android.Tasks.GetAndroidDefineConstants")]
public void RegisteredTaskNamesExecute (string taskName)
{
string directory = Path.Combine (Root, "temp", TestName);
Directory.CreateDirectory (directory);
string commonTargets = Path.Combine (NativeAotBootstrapTestTools.FindRepositoryRoot (),
"src", "Xamarin.Android.Build.Tasks", "Xamarin.Android.Common.targets");
var registrations = XDocument.Load (commonTargets).Descendants ()
.Where (e => e.Name.LocalName == "UsingTask" && (string?) e.Attribute ("TaskName") == "Microsoft.Android.Tasks.GetAndroidDefineConstants")
.Select (e => new XElement (e) { Name = "UsingTask" })
.ToArray ();
Assert.AreEqual (2, registrations.Length);

string project = Path.Combine (directory, "constants.proj");
string output = Path.Combine (directory, "constants.txt");
new XDocument (new XElement ("Project",
new XElement ("PropertyGroup",
new XElement ("_MicrosoftAndroidBuildTasksAssembly", typeof (GetAndroidDefineConstants).Assembly.Location)),
registrations,
new XElement ("Target", new XAttribute ("Name", "Build"),
new XElement (taskName,
new XAttribute ("AndroidApiLevel", "36.1"),
new XAttribute ("ProductVersion", "11.0-rc+test"),
new XElement ("Output", new XAttribute ("TaskParameter", "AndroidDefineConstants"), new XAttribute ("ItemName", "_Constants"))),
new XElement ("WriteLinesToFile",
new XAttribute ("File", output),
new XAttribute ("Lines", "@(_Constants)"),
new XAttribute ("Overwrite", "true")))))
.Save (project);

string dotnet = Environment.GetEnvironmentVariable ("DOTNET_HOST_PATH") ?? "dotnet";
var result = NativeAotBootstrapTestTools.Run (dotnet, "msbuild", project, "-t:Build", "-v:minimal", "-nr:false");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 💡 Testing — Consider adding a Windows-only variant that runs this generated project with full-framework MSBuild.exe. Both current cases invoke dotnet msbuild, so MSBuildRuntimeType is always Core; copying both registrations and asserting their count does not exercise the Full registration or the new out-of-process task-host boundary. Running the same output assertions through that host would protect the Visual Studio path when migrating this task out of the netstandard assembly.

{Rule: Test host-specific execution paths}

Assert.AreEqual (0, result.ExitCode, result.Output + result.Error);
var lines = File.ReadAllLines (output);
Assert.AreEqual ("__XAMARIN_ANDROID_11_0_rc_test__", lines [0]);
Assert.AreEqual ("__ANDROID_36_1__", lines [^1]);
}
}
}
4 changes: 2 additions & 2 deletions src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Link.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ string [] GenerateCommandLineCommands (string ManifestFile, string? currentAbi,
Directory.CreateDirectory (manifestDir);
string manifestFile = Path.Combine (manifestDir, Path.GetFileName (ManifestFile));
string targetSdkVersion = AndroidApiLevel;
if (MonoAndroidHelper.TryParseApiLevel (targetSdkVersion, out Version v)) {
if (MonoAndroidHelper.TryParseApiLevel (targetSdkVersion, out var v)) {
targetSdkVersion = v.Major.ToString (CultureInfo.InvariantCulture);
}
ManifestDocument manifest = new ManifestDocument (ManifestFile, versions);
Expand Down Expand Up @@ -341,7 +341,7 @@ string [] GenerateCommandLineCommands (string ManifestFile, string? currentAbi,
}
}
// Use $(SupportedOSPlatformVersion) if minSdkVersion was not found in the manifest
if (minSdkVersion.IsNullOrEmpty () && MonoAndroidHelper.TryParseApiLevel (SupportedOSPlatformVersion, out Version version)) {
if (minSdkVersion.IsNullOrEmpty () && MonoAndroidHelper.TryParseApiLevel (SupportedOSPlatformVersion, out var version)) {
minSdkVersion = version.Major.ToString (CultureInfo.InvariantCulture);
}
if (!minSdkVersion.IsNullOrEmpty ()) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;

Expand Down Expand Up @@ -222,4 +223,18 @@ public static bool StringEquals (string? value1, string? value2, StringCompariso
}
return value1.Equals (value2, comparisonType);
}

public static bool TryParseApiLevel (string? apiLevel, [NotNullWhen (true)] out Version? version)
{
if (Version.TryParse (apiLevel, out var v)) {
version = v;
return true;
}
if (int.TryParse (apiLevel, out var major)) {
version = new Version (major, 0);
return true;
}
version = null;
return false;
}
}
14 changes: 0 additions & 14 deletions src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -619,20 +619,6 @@ public static int ConvertSupportedOSPlatformVersionToApiLevel (string version)
return apiLevel;
}

public static bool TryParseApiLevel (string apiLevel, out Version version)
{
if (Version.TryParse (apiLevel, out var v)) {
version = v;
return true;
}
if (int.TryParse (apiLevel, out var major)) {
version = new Version (major, 0);
return true;
}
version = null;
return false;
}

#if MSBUILD
public static string GetAssemblyRid (ITaskItem asmItem)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateResourceDesignerAssembly" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Microsoft.Android.Tasks.GeneratePackageManagerJava" AssemblyFile="$(_MicrosoftAndroidBuildTasksAssembly)" Runtime="NET" TaskFactory="TaskHostFactory" Condition=" '$(MSBuildRuntimeType)' == 'Full' " />
<UsingTask TaskName="Microsoft.Android.Tasks.GeneratePackageManagerJava" AssemblyFile="$(_MicrosoftAndroidBuildTasksAssembly)" Runtime="NET" Condition=" '$(MSBuildRuntimeType)' == 'Core' " />
<UsingTask TaskName="Xamarin.Android.Tasks.GetAndroidDefineConstants" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Microsoft.Android.Tasks.GetAndroidDefineConstants" AssemblyFile="$(_MicrosoftAndroidBuildTasksAssembly)" Runtime="NET" TaskFactory="TaskHostFactory" Condition=" '$(MSBuildRuntimeType)' == 'Full' " />
<UsingTask TaskName="Microsoft.Android.Tasks.GetAndroidDefineConstants" AssemblyFile="$(_MicrosoftAndroidBuildTasksAssembly)" Runtime="NET" Condition=" '$(MSBuildRuntimeType)' == 'Core' " />
<UsingTask TaskName="Xamarin.Android.Tasks.KeyTool" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.LinkAssembliesNoShrink" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.Lint" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
Expand Down
Loading