[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:
Родитель
8606b32d07
Коммит
c0f492f938
|
@ -8,6 +8,7 @@
|
||||||
<_DotNetRootRemoteDirectory Condition="$(_DotNetRootRemoteDirectory) == ''">/usr/local/share/dotnet/</_DotNetRootRemoteDirectory>
|
<_DotNetRootRemoteDirectory Condition="$(_DotNetRootRemoteDirectory) == ''">/usr/local/share/dotnet/</_DotNetRootRemoteDirectory>
|
||||||
<_XamarinSdkRootDirectoryOnMac Condition="'$(_XamarinSdkRootDirectory)' != ''">$(_XamarinSdkRootDirectory.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)'))</_XamarinSdkRootDirectoryOnMac>
|
<_XamarinSdkRootDirectoryOnMac Condition="'$(_XamarinSdkRootDirectory)' != ''">$(_XamarinSdkRootDirectory.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)'))</_XamarinSdkRootDirectoryOnMac>
|
||||||
<_MlaunchPath Condition="'$(_MlaunchPath)' == ''">$(_XamarinSdkRootDirectoryOnMac)tools/bin/mlaunch</_MlaunchPath>
|
<_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>
|
<AfterMicrosoftNETSdkTargets>$(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)..\targets\Microsoft.iOS.Windows.Sdk.targets</AfterMicrosoftNETSdkTargets>
|
||||||
|
|
||||||
<_XamarinSdkRootOnMac Condition="'$(_XamarinSdkRoot)' != ''">$(_XamarinSdkRoot.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)'))</_XamarinSdkRootOnMac>
|
<_XamarinSdkRootOnMac Condition="'$(_XamarinSdkRoot)' != ''">$(_XamarinSdkRoot.Replace('$(NetCoreRoot)', '$(_DotNetRootRemoteDirectory)'))</_XamarinSdkRootOnMac>
|
||||||
|
|
|
@ -1817,34 +1817,51 @@
|
||||||
<!-- Install & Run -->
|
<!-- Install & Run -->
|
||||||
|
|
||||||
<PropertyGroup>
|
<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>
|
</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 -->
|
<!-- 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="$([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
|
<GetMlaunchArguments
|
||||||
SessionId="$(BuildSessionId)"
|
SessionId="$(BuildSessionId)"
|
||||||
AppBundlePath="$(_AppBundlePath)"
|
AppBundlePath="$(_AppBundlePath)"
|
||||||
AppManifestPath="$(_AppBundleManifestPath)"
|
AppManifestPath="$(_AppBundleManifestPath)"
|
||||||
DeviceName="$(_DeviceName)"
|
DeviceName="$(_DeviceName)"
|
||||||
InstallApp="$(_AppBundlePath)"
|
InstallApp="$(_AppBundlePath)"
|
||||||
MlaunchPath="$(_MlaunchPath)"
|
MlaunchPath="$(MlaunchPath)"
|
||||||
SdkDevPath="$(_SdkDevPath)"
|
SdkDevPath="$(_SdkDevPath)"
|
||||||
SdkIsSimulator="$(_SdkIsSimulator)"
|
SdkIsSimulator="$(_SdkIsSimulator)"
|
||||||
SdkVersion="$(_SdkVersion)"
|
SdkVersion="$(_SdkVersion)"
|
||||||
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
|
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
|
||||||
>
|
>
|
||||||
<Output TaskParameter="MlaunchArguments" PropertyName="_MlaunchInstallArguments" />
|
<Output TaskParameter="MlaunchArguments" PropertyName="MlaunchInstallArguments" />
|
||||||
</GetMlaunchArguments>
|
</GetMlaunchArguments>
|
||||||
|
|
||||||
<Exec SessionId="$(BuildSessionId)" Command="$(_MlaunchPath) $(_MlaunchInstallArguments)" />
|
<WriteLinesToFile
|
||||||
|
File="$(MlaunchInstallScript)"
|
||||||
|
Lines="$(MlaunchPath) $(MlaunchInstallArguments)"
|
||||||
|
Overwrite="true"
|
||||||
|
WriteOnlyWhenDifferent="true"
|
||||||
|
Condition="'$(MlaunchInstallScript)' != ''"
|
||||||
|
/>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<!-- This is only needed for mobile platforms, RunCommand and RunArguments are defined for macOS in Microsoft.macOS.Sdk.targets. -->
|
<Target Name="_InstallMobile" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName;ComputeMlaunchInstallArguments" Condition="'$(_SdkIsSimulator)' == 'false'">
|
||||||
<Target Name="_PrepareRunMobile" DependsOnTargets="_InstallMobile" Condition="'$(_PlatformName)' != 'macOS' And '$(_PlatformName)' != 'MacCatalyst'">
|
<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 -->
|
<!-- 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="$([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>
|
<PropertyGroup>
|
||||||
<!-- capture output by default -->
|
<!-- capture output by default -->
|
||||||
<_MlaunchCaptureOutput Condition="'$(_MlaunchCaptureOutput)' == ''">true</_MlaunchCaptureOutput>
|
<_MlaunchCaptureOutput Condition="'$(_MlaunchCaptureOutput)' == ''">true</_MlaunchCaptureOutput>
|
||||||
|
@ -1869,7 +1886,7 @@
|
||||||
DeviceName="$(_DeviceName)"
|
DeviceName="$(_DeviceName)"
|
||||||
EnvironmentVariables="@(MlaunchEnvironmentVariables)"
|
EnvironmentVariables="@(MlaunchEnvironmentVariables)"
|
||||||
LaunchApp="$(_AppBundlePath)"
|
LaunchApp="$(_AppBundlePath)"
|
||||||
MlaunchPath="$(_MlaunchPath)"
|
MlaunchPath="$(MlaunchPath)"
|
||||||
SdkIsSimulator="$(_SdkIsSimulator)"
|
SdkIsSimulator="$(_SdkIsSimulator)"
|
||||||
SdkDevPath="$(_SdkDevPath)"
|
SdkDevPath="$(_SdkDevPath)"
|
||||||
SdkVersion="$(_SdkVersion)"
|
SdkVersion="$(_SdkVersion)"
|
||||||
|
@ -1878,12 +1895,23 @@
|
||||||
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
|
TargetFrameworkMoniker="$(_ComputedTargetFrameworkMoniker)"
|
||||||
WaitForExit="$(_MlaunchWaitForExit)"
|
WaitForExit="$(_MlaunchWaitForExit)"
|
||||||
>
|
>
|
||||||
<Output TaskParameter="MlaunchArguments" PropertyName="_MlaunchRunArguments" />
|
<Output TaskParameter="MlaunchArguments" PropertyName="MlaunchRunArguments" />
|
||||||
</GetMlaunchArguments>
|
</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>
|
<PropertyGroup>
|
||||||
<RunCommand>$(_MlaunchPath)</RunCommand>
|
<RunCommand>$(MlaunchPath)</RunCommand>
|
||||||
<RunArguments>$(_MlaunchRunArguments)</RunArguments>
|
<RunArguments>$(MlaunchRunArguments)</RunArguments>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
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
|
// Returns a diagnostic build log as a string
|
||||||
public static string PrintToString (string path)
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче