Skip to content

Commit

Permalink
[release/7.0.2xx-xcode14.3] [dotnet] Add targets to compute mlaunch a…
Browse files Browse the repository at this point in the history
…rguments 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 #18359.

Backport of #18446.

---------

Co-authored-by: GitHub Actions Autoformatter <github-actions-autoformatter@xamarin.com>
  • Loading branch information
rolfbjarne and GitHub Actions Autoformatter committed Jun 16, 2023
1 parent 8606b32 commit c0f492f
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
50 changes: 39 additions & 11 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -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>

<Target Name="_InstallMobile" DependsOnTargets="_DetectSdkLocations;_GenerateBundleName;ComputeMlaunchInstallArguments" Condition="'$(_SdkIsSimulator)' == 'false'">
<Exec SessionId="$(BuildSessionId)" Command="$(MlaunchPath) $(MlaunchInstallArguments)" />
</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="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>
Expand All @@ -1869,7 +1886,7 @@
DeviceName="$(_DeviceName)"
EnvironmentVariables="@(MlaunchEnvironmentVariables)"
LaunchApp="$(_AppBundlePath)"
MlaunchPath="$(_MlaunchPath)"
MlaunchPath="$(MlaunchPath)"
SdkIsSimulator="$(_SdkIsSimulator)"
SdkDevPath="$(_SdkDevPath)"
SdkVersion="$(_SdkVersion)"
Expand All @@ -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>

Expand Down
41 changes: 41 additions & 0 deletions tests/common/BinLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;

Expand Down Expand Up @@ -239,6 +240,46 @@ public static IEnumerable<BuildLogEvent> GetBuildMessages (string path)
}
}

#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)
{
Expand Down
97 changes: 97 additions & 0 deletions tests/dotnet/UnitTests/MlaunchTest.cs
Original file line number Diff line number Diff line change
@@ -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");
}
}
}

6 comments on commit c0f492f

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

Please sign in to comment.