[release/7.0.2xx-xcode14.3] [dotnet] Add targets to compute mlaunch arguments for installing and launching mobile apps. Fixes #18359. (#18451)

Add public targets to compute the mlaunch command lines for installing
and launching mobile apps.

These new targets are:

* ComputeMlaunchInstallArguments
* ComputeMlaunchRunArguments

As part of this change, also create a few new public properties:

* MlaunchPath
* MlaunchRunArguments
* MlaunchInstallArguments
* MlaunchRunScript
* MlaunchInstallScript

If the *Script variables are set, the corresponding target will create a
script file with the path to mlaunch + the corresponding arguments.

Otherwise, it's also possible to get the arguments directly from the
build log.

Fixes https://github.com/xamarin/xamarin-macios/issues/18359.

Backport of #18446.

---------

Co-authored-by: GitHub Actions Autoformatter <github-actions-autoformatter@xamarin.com>
This commit is contained in:
Rolf Bjarne Kvinge 2023-06-16 15:09:35 +02:00 коммит произвёл GitHub
Родитель 8606b32d07
Коммит c0f492f938
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 178 добавлений и 11 удалений

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

@ -8,6 +8,7 @@
<_DotNetRootRemoteDirectory Condition="$(_DotNetRootRemoteDirectory) == ''">/usr/local/share/dotnet/</_DotNetRootRemoteDirectory>
<_XamarinSdkRootDirectoryOnMac Condition="'$(_XamarinSdkRootDirectory)' != ''">$(_XamarinSdkRootDirectory.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)'))</_XamarinSdkRootDirectoryOnMac>
<_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(_XamarinSdkRootDirectoryOnMac)tools/bin/mlaunch</_MlaunchPath>
<MlaunchPath Condition="'$(MlaunchPath)' == ''">$(_XamarinSdkRootDirectoryOnMac)tools/bin/mlaunch</MlaunchPath>
<AfterMicrosoftNETSdkTargets>$(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)..\targets\Microsoft.iOS.Windows.Sdk.targets</AfterMicrosoftNETSdkTargets>
<_XamarinSdkRootOnMac Condition="'$(_XamarinSdkRoot)' != ''">$(_XamarinSdkRoot.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)'))</_XamarinSdkRootOnMac>

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

@ -1817,34 +1817,51 @@
<!-- Install & Run -->
<PropertyGroup>
<_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(_XamarinSdkRootDirectory)tools\bin\mlaunch</_MlaunchPath>
<!-- We used to use '_MlaunchPath' as the property name, but we've made it public, so it's MlaunchPath now, but keep setting/supporting the underscored version for a while -->
<MlaunchPath Condition="'$(MlaunchPath)' == '' And '$(_MlaunchPath)' != ''">$(_MlaunchPath)</MlaunchPath>
<MlaunchPath Condition="'$(MlaunchPath)' == ''">$(_XamarinSdkRootDirectory)tools\bin\mlaunch</MlaunchPath>
<_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(MlaunchPath)</_MlaunchPath>
</PropertyGroup>
<Target Name="_InstallMobile" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName" Condition="'$(_SdkIsSimulator)' == 'false'">
<Target Name="ComputeMlaunchInstallArguments" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName;_DetectAppManifest;_ComputeMlaunchInstallArguments" />
<Target Name="_ComputeMlaunchInstallArguments" Condition="'$(_SdkIsSimulator)' == 'false'">
<!-- Launching from the command line on windows hasn't been implemented: https://github.com/xamarin/xamarin-macios/issues/16609 -->
<Error Condition="$([MSBuild]::IsOSPlatform('windows'))" Text="It's currently not supported to launch an app from the command line on Windows." />
<Error Condition="!Exists('$(_AppBundleManifestPath)')" Text="The app must be built before the arguments to launch the app using mlaunch can be computed." />
<GetMlaunchArguments
SessionId="$(BuildSessionId)"
AppBundlePath="$(_AppBundlePath)"
AppManifestPath="$(_AppBundleManifestPath)"
DeviceName="$(_DeviceName)"
InstallApp="$(_AppBundlePath)"
MlaunchPath="$(_MlaunchPath)"
MlaunchPath="$(MlaunchPath)"
SdkDevPath="$(_SdkDevPath)"
SdkIsSimulator="$(_SdkIsSimulator)"
SdkVersion="$(_SdkVersion)"
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
>
<Output TaskParameter="MlaunchArguments" PropertyName="_MlaunchInstallArguments" />
<Output TaskParameter="MlaunchArguments" PropertyName="MlaunchInstallArguments" />
</GetMlaunchArguments>
<Exec SessionId="$(BuildSessionId)" Command="$(_MlaunchPath) $(_MlaunchInstallArguments)" />
<WriteLinesToFile
File="$(MlaunchInstallScript)"
Lines="$(MlaunchPath) $(MlaunchInstallArguments)"
Overwrite="true"
WriteOnlyWhenDifferent="true"
Condition="'$(MlaunchInstallScript)' != ''"
/>
</Target>
<!-- This is only needed for mobile platforms, RunCommand and RunArguments are defined for macOS in Microsoft.macOS.Sdk.targets. -->
<Target Name="_PrepareRunMobile" DependsOnTargets="_InstallMobile" Condition="'$(_PlatformName)' != 'macOS' And '$(_PlatformName)' != 'MacCatalyst'">
<Target Name="_InstallMobile" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName;ComputeMlaunchInstallArguments" Condition="'$(_SdkIsSimulator)' == 'false'">
<Exec SessionId="$(BuildSessionId)" Command="$(MlaunchPath) $(MlaunchInstallArguments)" />
</Target>
<Target Name="ComputeMlaunchRunArguments" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName;_DetectAppManifest" Condition="'$(_PlatformName)' != 'macOS' And '$(_PlatformName)' != 'MacCatalyst'">
<!-- Launching from the command line on windows hasn't been implemented: https://github.com/xamarin/xamarin-macios/issues/16609 -->
<Error Condition="$([MSBuild]::IsOSPlatform('windows'))" Text="It's currently not supported to launch an app from the command line on Windows." />
<Error Condition="!Exists('$(_AppBundleManifestPath)')" Text="The app must be built before the arguments to launch the app using mlaunch can be computed." />
<PropertyGroup>
<!-- capture output by default -->
<_MlaunchCaptureOutput Condition="'$(_MlaunchCaptureOutput)' == ''">true</_MlaunchCaptureOutput>
@ -1869,7 +1886,7 @@
DeviceName="$(_DeviceName)"
EnvironmentVariables="@(MlaunchEnvironmentVariables)"
LaunchApp="$(_AppBundlePath)"
MlaunchPath="$(_MlaunchPath)"
MlaunchPath="$(MlaunchPath)"
SdkIsSimulator="$(_SdkIsSimulator)"
SdkDevPath="$(_SdkDevPath)"
SdkVersion="$(_SdkVersion)"
@ -1878,12 +1895,23 @@
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
WaitForExit="$(_MlaunchWaitForExit)"
>
<Output TaskParameter="MlaunchArguments" PropertyName="_MlaunchRunArguments" />
<Output TaskParameter="MlaunchArguments" PropertyName="MlaunchRunArguments" />
</GetMlaunchArguments>
<WriteLinesToFile
File="$(MlaunchRunScript)"
Lines="$(MlaunchPath) $(MlaunchRunArguments)"
Overwrite="true"
WriteOnlyWhenDifferent="true"
Condition="'$(MlaunchRunScript)' != ''"
/>
</Target>
<!-- This is only needed for mobile platforms, RunCommand and RunArguments are defined for macOS in Microsoft.macOS.Sdk.targets. -->
<Target Name="_PrepareRunMobile" DependsOnTargets="_InstallMobile;ComputeMlaunchRunArguments" Condition="'$(_PlatformName)' != 'macOS' And '$(_PlatformName)' != 'MacCatalyst'">
<PropertyGroup>
<RunCommand>$(_MlaunchPath)</RunCommand>
<RunArguments>$(_MlaunchRunArguments)</RunArguments>
<RunCommand>$(MlaunchPath)</RunCommand>
<RunArguments>$(MlaunchRunArguments)</RunArguments>
</PropertyGroup>
</Target>

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

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
@ -239,6 +240,46 @@ namespace Xamarin.Tests {
}
}
#if NET
public static bool TryFindPropertyValue (string binlog, string property, [NotNullWhen (true)] out string? value)
#else
public static bool TryFindPropertyValue (string binlog, string property, out string? value)
#endif
{
value = null;
var reader = new BinLogReader ();
foreach (var record in reader.ReadRecords (binlog)) {
var args = record?.Args;
if (args is null)
continue;
if (args is PropertyInitialValueSetEventArgs pivsea) {
if (string.Equals (property, pivsea.PropertyName, StringComparison.OrdinalIgnoreCase))
value = pivsea.PropertyValue;
} else if (args is PropertyReassignmentEventArgs prea) {
if (string.Equals (property, prea.PropertyName, StringComparison.OrdinalIgnoreCase))
value = prea.NewValue;
} else if (args is ProjectEvaluationFinishedEventArgs pefea) {
var dict = pefea.Properties as IDictionary<string, string>;
if (dict is not null && dict.TryGetValue (property, out var pvalue))
value = pvalue;
} else if (args is BuildMessageEventArgs bmea) {
if (bmea.Message.StartsWith ("Output Property: ", StringComparison.Ordinal)) {
var kvp = bmea.Message.Substring ("Output Property: ".Length);
var eq = kvp.IndexOf ('=');
if (eq > 0) {
var propname = kvp.Substring (0, eq);
var propvalue = kvp.Substring (eq + 1);
if (propname == property)
value = propvalue;
}
}
}
}
return value is not null;
}
// Returns a diagnostic build log as a string
public static string PrintToString (string path)
{

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

@ -0,0 +1,97 @@
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using Mono.Cecil;
using Xamarin.Tests;
#nullable enable
namespace Xamarin.Tests {
[TestFixture]
public class MlaunchTest : TestBaseClass {
[Test]
[TestCase (ApplePlatform.iOS, "ios-arm64")]
[TestCase (ApplePlatform.TVOS, "tvos-arm64")]
public void GetMlaunchInstallArguments (ApplePlatform platform, string runtimeIdentifiers)
{
var project = "MySimpleApp";
Configuration.IgnoreIfIgnoredPlatform (platform);
Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers);
var outputPath = Path.Combine (Cache.CreateTemporaryDirectory (), "install.sh");
var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath);
var properties = GetDefaultProperties (runtimeIdentifiers);
properties ["EnableCodeSigning"] = "false"; // Skip code signing, since that would require making sure we have code signing configured on bots.
// Create the app manifest first, since it's required to compute the mlaunch install arguments
DotNet.Execute ("build", project_path, properties, target: "_DetectSdkLocations;_DetectAppManifest;_CompileAppManifest;_WriteAppManifest");
properties ["MlaunchInstallScript"] = outputPath;
var rv = DotNet.Execute ("build", project_path, properties, target: "ComputeMlaunchInstallArguments");
if (!BinLog.TryFindPropertyValue (rv.BinLogPath, "MlaunchInstallArguments", out var mlaunchInstallArguments))
Assert.Fail ("Could not find the property 'MlaunchInstallArguments' in the binlog.");
if (!BinLog.TryFindPropertyValue (rv.BinLogPath, "MlaunchPath", out var mlaunchPath))
Assert.Fail ("Could not find the property 'MlaunchPath' in the binlog.");
Assert.That (mlaunchPath, Does.Exist, "mlaunch existence");
var expectedArguments = new StringBuilder ();
expectedArguments.Append ("--installdev ");
expectedArguments.Append (appPath.Substring (Path.GetDirectoryName (project_path)!.Length + 1)).Append ('/');
expectedArguments.Append ($" --wait-for-exit:false");
Assert.AreEqual (expectedArguments.ToString (), mlaunchInstallArguments);
var scriptContents = File.ReadAllText (outputPath).Trim ('\n'); ;
var expectedScriptContents = mlaunchPath + " " + expectedArguments.ToString ();
Assert.AreEqual (expectedScriptContents, scriptContents, "Script contents");
}
[Test]
[TestCase (ApplePlatform.iOS, "iossimulator-x64;iossimulator-arm64", ":v2:runtime=com.apple.CoreSimulator.SimRuntime.iOS-16-4,devicetype=com.apple.CoreSimulator.SimDeviceType.iPhone-14-Pro")]
[TestCase (ApplePlatform.iOS, "ios-arm64", "")]
[TestCase (ApplePlatform.TVOS, "tvossimulator-arm64", ":v2:runtime=com.apple.CoreSimulator.SimRuntime.tvOS-16-4,devicetype=com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-3rd-generation-1080p")]
public void GetMlaunchRunArguments (ApplePlatform platform, string runtimeIdentifiers, string device)
{
var project = "MySimpleApp";
Configuration.IgnoreIfIgnoredPlatform (platform);
Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers);
var outputPath = Path.Combine (Cache.CreateTemporaryDirectory (), "launch.sh");
var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath);
var properties = GetDefaultProperties (runtimeIdentifiers);
properties ["EnableCodeSigning"] = "false"; // Skip code signing, since that would require making sure we have code signing configured on bots.
// Create the app manifest first, since it's required to compute the mlaunch run arguments
DotNet.Execute ("build", project_path, properties, target: "_DetectSdkLocations;_DetectAppManifest;_CompileAppManifest;_WriteAppManifest");
properties ["MlaunchRunScript"] = outputPath;
var rv = DotNet.Execute ("build", project_path, properties, target: "ComputeMlaunchRunArguments");
if (!BinLog.TryFindPropertyValue (rv.BinLogPath, "MlaunchRunArguments", out var mlaunchRunArguments))
Assert.Fail ("Could not find the property 'MlaunchRunArguments' in the binlog.");
if (!BinLog.TryFindPropertyValue (rv.BinLogPath, "MlaunchPath", out var mlaunchPath))
Assert.Fail ("Could not find the property 'MlaunchPath' in the binlog.");
Assert.That (mlaunchPath, Does.Exist, "mlaunch existence");
var expectedArguments = new StringBuilder ();
var isSim = runtimeIdentifiers.Contains ("simulator");
expectedArguments.Append (isSim ? "--launchsim " : "--launchdev ");
expectedArguments.Append (appPath.Substring (Path.GetDirectoryName (project_path)!.Length + 1)).Append ('/');
if (isSim) {
expectedArguments.Append (" --device \"");
expectedArguments.Append (device);
expectedArguments.Append ('"');
}
expectedArguments.Append ($" --wait-for-exit:true");
Assert.AreEqual (expectedArguments.ToString (), mlaunchRunArguments);
var scriptContents = File.ReadAllText (outputPath).Trim ('\n'); ;
var expectedScriptContents = mlaunchPath + " " + expectedArguments.ToString ();
Assert.AreEqual (expectedScriptContents, scriptContents, "Script contents");
}
}
}