[msbuild] Port Ditto to subclass XamarinTask.

This has a few advantages:

* We simplify and unify more of our code.
* We have more control over the error reporting / logging behavior.

Additionally:

* Allow for overriding the path to the command-line tool in question.
* Add support for cancellation.

Fixes https://github.com/xamarin/xamarin-macios/issues/21437.
This commit is contained in:
Rolf Bjarne Kvinge 2024-10-16 11:37:52 +02:00
Родитель 1fddf207e4
Коммит 894e604d61
7 изменённых файлов: 63 добавлений и 52 удалений

Просмотреть файл

@ -11,6 +11,12 @@ MSBuild properties control the behavior of the
They're specified within the project file, for example **MyApp.csproj**, within
an MSBuild PropertyGroup.
## DittoPath
The full path to the `ditto` executable.
The default behavior is to use `/usr/bin/ditto`.
## MaciOSPrepareForBuildDependsOn
A semi-colon delimited property that can be used to extend the build process.

Просмотреть файл

@ -869,8 +869,7 @@
Condition="'$(IsMacEnabled)' == 'true'"
AdditionalArguments="$(_DittoArchitectures)"
CopyFromWindows="true"
ToolExe="$(DittoExe)"
ToolPath="$(DittoPath)"
DittoPath="$(DittoPath)"
Source="%(_DirectoriesToPublish.SourceDirectory)"
Destination="%(_DirectoriesToPublish.TargetDirectory)"
TouchDestinationFiles="true"

Просмотреть файл

@ -1576,6 +1576,19 @@
<comment>SupportedOSPlatformVersion: don't translate (it's the name of an MSBuild property)</comment>
</data>
<data name="E7131" xml:space="preserve">
<value>The source '{0}' does not exist.</value>
<comment>{0}: path to a file or a directory</comment>
</data>
<data name="E7132" xml:space="preserve">
<value>Unable to parse the 'AdditionalArguments' value: {0}</value>
<comment>
AdditionalArguments: don't translate (it's the name of an MSBuild property)
{0}: additional arguments passed to the task
</comment>
</data>
<data name="XcodeBuild_CreateNativeRef" xml:space="preserve">
<value>Adding reference to Xcode project output: '{0}'. The '%(CreateNativeReference)' metadata can be set to 'false' to opt out of this behavior.</value>
<comment>

Просмотреть файл

@ -4,14 +4,19 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Xamarin.Localization.MSBuild;
using Xamarin.Messaging.Build.Client;
using Xamarin.Utils;
namespace Xamarin.MacDev.Tasks {
public class Ditto : XamarinToolTask, ITaskCallback {
public class Ditto : XamarinTask, ITaskCallback, ICancelableTask {
CancellationTokenSource? cancellationTokenSource;
#region Inputs
public string? AdditionalArguments { get; set; }
@ -26,6 +31,8 @@ namespace Xamarin.MacDev.Tasks {
// the mode.
public bool CopyFromWindows { get; set; }
public string? DittoPath { get; set; }
[Required]
public ITaskItem? Source { get; set; }
@ -40,32 +47,6 @@ namespace Xamarin.MacDev.Tasks {
#endregion
protected override string ToolName {
get { return "ditto"; }
}
protected override string GenerateFullPathToTool ()
{
if (!string.IsNullOrEmpty (ToolPath))
return Path.Combine (ToolPath, ToolExe);
var path = Path.Combine ("/usr/bin", ToolExe);
return File.Exists (path) ? path : ToolExe;
}
protected override string GenerateCommandLineCommands ()
{
var args = new CommandLineArgumentBuilder ();
args.AddQuoted (Path.GetFullPath (Source!.ItemSpec));
args.AddQuoted (Path.GetFullPath (Destination!.ItemSpec));
if (!string.IsNullOrEmpty (AdditionalArguments))
args.Add (AdditionalArguments);
return args.ToString ();
}
public override bool Execute ()
{
if (ShouldExecuteRemotely ()) {
@ -76,8 +57,31 @@ namespace Xamarin.MacDev.Tasks {
return taskRunner.RunAsync (this).Result;
}
if (!base.Execute ())
var src = Source!.ItemSpec;
if (!File.Exists (src) && !Directory.Exists (src)) {
Log.LogError (MSBStrings.E7131 /* The source '{0}' does not exist. */, src);
return false;
}
var executable = string.IsNullOrEmpty (DittoPath) ? "/usr/bin/ditto" : DittoPath!;
var args = new List<string> ();
args.Add (Path.GetFullPath (Source!.ItemSpec));
args.Add (Path.GetFullPath (Destination!.ItemSpec));
#if NET
if (!string.IsNullOrEmpty (AdditionalArguments)) {
#else
if (AdditionalArguments is not null && !string.IsNullOrEmpty (AdditionalArguments)) {
#endif
if (StringUtils.TryParseArguments (AdditionalArguments, out var additionalArgs, out var ex)) {
args.AddRange (additionalArgs);
} else {
Log.LogError (MSBStrings.E7132 /* Unable to parse the 'AdditionalArguments' value: {0} */, AdditionalArguments);
return false;
}
}
cancellationTokenSource = new CancellationTokenSource ();
ExecuteAsync (Log, executable, args, cancellationToken: cancellationTokenSource.Token).Wait ();
// Create a list of all the files we've copied
var copiedFiles = new List<ITaskItem> ();
@ -96,18 +100,13 @@ namespace Xamarin.MacDev.Tasks {
return !Log.HasLoggedErrors;
}
protected override void LogEventsFromTextOutput (string singleLine, MessageImportance messageImportance)
public void Cancel ()
{
// TODO: do proper parsing of error messages and such
Log.LogMessage (messageImportance, "{0}", singleLine);
}
public override void Cancel ()
{
base.Cancel ();
if (ShouldExecuteRemotely ())
if (ShouldExecuteRemotely ()) {
BuildConnection.CancelAsync (BuildEngine4).Wait ();
} else {
cancellationTokenSource?.Cancel ();
}
}
public IEnumerable<ITaskItem> GetAdditionalItemsToBeCopied ()

Просмотреть файл

@ -2505,8 +2505,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<Ditto
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
ToolExe="$(DittoExe)"
ToolPath="$(DittoPath)"
DittoPath="$(DittoPath)"
Source="@(_ResolvedAppExtensionReferences)"
Destination="$(_AppExtensionRoot)%(_ResolvedAppExtensionReferences.ContainerName)\%(_ResolvedAppExtensionReferences.FileName)%(_ResolvedAppExtensionReferences.Extension)"
TouchDestinationFiles="true"

Просмотреть файл

@ -81,8 +81,7 @@ Copyright (C) 2015-2016 Xamarin. All rights reserved.
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)'"
AdditionalArguments="$(WKDittoArchitectures)"
ToolExe="$(DittoExe)"
ToolPath="$(DittoPath)"
DittoPath="$(DittoPath)"
Source="$(_NativeWatchApp)"
Destination="$(_AppBundlePath)$(AssemblyName)"
/>
@ -93,8 +92,7 @@ Copyright (C) 2015-2016 Xamarin. All rights reserved.
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)'"
AdditionalArguments="$(WKDittoArchitectures)"
ToolExe="$(DittoExe)"
ToolPath="$(DittoPath)"
DittoPath="$(DittoPath)"
Source="$(_NativeWatchApp)"
Destination="$(_AppBundlePath)_WatchKitStub\WK"
/>

Просмотреть файл

@ -371,8 +371,7 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved.
<Ditto
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true' And '@(_ResolvedWatchAppReferences)' != '' And '%(_ResolvedWatchAppReferences.Identity)' != ''"
ToolExe="$(DittoExe)"
ToolPath="$(DittoPath)"
DittoPath="$(DittoPath)"
Source="@(_ResolvedWatchAppReferences)"
Destination="$(_AppBundlePath)Watch\%(_ResolvedWatchAppReferences.FileName)%(_ResolvedWatchAppReferences.Extension)"
/>
@ -391,8 +390,7 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved.
<Ditto
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true'"
ToolExe="$(DittoExe)"
ToolPath="$(DittoPath)"
DittoPath="$(DittoPath)"
Source="$(AppBundleDir)"
Destination="$(_IpaAppBundleDir)"
/>
@ -481,8 +479,7 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved.
<Ditto
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true' And Exists('$(DeviceSpecificOutputPath)OnDemandResources\')"
ToolExe="$(DittoExe)"
ToolPath="$(DittoPath)"
DittoPath="$(DittoPath)"
Source="$(DeviceSpecificOutputPath)OnDemandResources\"
Destination="$(_IntermediateODRDir)"
/>