4
4
5
5
using System ;
6
6
using System . IO ;
7
- using System . Linq ;
8
7
using System . Text . RegularExpressions ;
9
8
using Microsoft . DotNet . XHarness . Common . Logging ;
10
9
using Microsoft . DotNet . XHarness . iOS . Shared ;
@@ -25,58 +24,85 @@ public interface IMacCatalystExitCodeDetector : IExitCodeDetector
25
24
26
25
public abstract class ExitCodeDetector : IExitCodeDetector
27
26
{
28
- public int ? DetectExitCode ( AppBundleInformation appBundleInfo , IReadableLog systemLog )
27
+ // This tag is logged by the dotnet/runtime Apple app wrapper
28
+ // https://github.com/dotnet/runtime/blob/a883caa0803778084167b978281c34db8e753246/src/tasks/AppleAppBuilder/Templates/runtime.m#L30
29
+ protected const string DotnetAppExitTag = "DOTNET.APP_EXIT_CODE:" ;
30
+
31
+ // This line is logged by MacOS
32
+ protected const string AbnormalExitMessage = "Service exited with abnormal code" ;
33
+
34
+ public int ? DetectExitCode ( AppBundleInformation appBundleInfo , IReadableLog log )
29
35
{
30
36
StreamReader reader ;
31
37
32
38
try
33
39
{
34
- reader = systemLog . GetReader ( ) ;
40
+ reader = log . GetReader ( ) ;
35
41
}
36
42
catch ( FileNotFoundException e )
37
43
{
38
- throw new Exception ( "Failed to detect application's exit code. The system log was empty / not found at " + e . FileName ) ;
44
+ throw new Exception ( "Failed to detect application's exit code. The log file was empty / not found at " + e . FileName ) ;
39
45
}
40
46
41
47
using ( reader )
42
- while ( ! reader . EndOfStream )
48
+ while ( ! reader . EndOfStream )
49
+ {
50
+ if ( reader . ReadLine ( ) is string line
51
+ && IsSignalLine ( appBundleInfo , line ) is Match match && match . Success
52
+ && int . TryParse ( match . Groups [ "exitCode" ] . Value , out var exitCode ) )
43
53
{
44
- var line = reader . ReadLine ( ) ;
54
+ return exitCode ;
55
+ }
56
+ }
45
57
46
- if ( ! string . IsNullOrEmpty ( line ) && IsSignalLine ( appBundleInfo , line ) )
47
- {
48
- var match = ExitCodeRegex . Match ( line ) ;
58
+ return null ;
59
+ }
49
60
50
- if ( match . Success && int . TryParse ( match . Captures . First ( ) . Value , out var exitCode ) )
51
- {
52
- return exitCode ;
53
- }
54
- }
55
- }
61
+ protected virtual Match ? IsSignalLine ( AppBundleInformation appBundleInfo , string logLine )
62
+ {
63
+ if ( IsAbnormalExitLine ( appBundleInfo , logLine ) || IsStdoutExitLine ( appBundleInfo , logLine ) )
64
+ {
65
+ return EoLExitCodeRegex . Match ( logLine ) ;
66
+ }
56
67
57
68
return null ;
58
69
}
59
70
60
- protected abstract bool IsSignalLine ( AppBundleInformation appBundleInfo , string logLine ) ;
71
+ protected Regex EoLExitCodeRegex { get ; } = new Regex ( @" (?<exitCode>-?[0-9]+)$" , RegexOptions . Compiled ) ;
72
+
73
+ // Example line coming from app's stdout log stream
74
+ // 2022-03-18 12:48:53.336 I Microsoft.Extensions.Configuration.CommandLine.Tests[12477:10069] DOTNET.APP_EXIT_CODE: 0
75
+ private static bool IsStdoutExitLine ( AppBundleInformation appBundleInfo , string logLine ) =>
76
+ logLine . Contains ( DotnetAppExitTag ) && logLine . Contains ( appBundleInfo . BundleExecutable ?? appBundleInfo . BundleIdentifier ) ;
61
77
62
- protected virtual Regex ExitCodeRegex { get ; } = new Regex ( " (\\ -?[0-9]+)$" , RegexOptions . Compiled ) ;
78
+ // Example line
79
+ // Feb 18 06:40:16 Admins-Mac-Mini com.apple.xpc.launchd[1] (net.dot.System.Buffers.Tests.15140[59229]): Service exited with abnormal code: 74
80
+ private static bool IsAbnormalExitLine ( AppBundleInformation appBundleInfo , string logLine ) =>
81
+ logLine . Contains ( AbnormalExitMessage ) && ( logLine . Contains ( appBundleInfo . AppName ) || logLine . Contains ( appBundleInfo . BundleIdentifier ) ) ;
63
82
}
64
83
65
84
public class iOSExitCodeDetector : ExitCodeDetector , IiOSExitCodeDetector
66
85
{
67
- // Example line
68
- // Nov 18 04:31:44 ML-MacVM com.apple.CoreSimulator.SimDevice.2E1EE736-5672-4220-89B5-B7C77DB6AF18[55655] (UIKitApplication:net.dot.HelloiOS[9a0b][rb-legacy][57331]): Service exited with abnormal code: 200
69
- protected override bool IsSignalLine ( AppBundleInformation appBundleInfo , string logLine ) =>
70
- logLine . Contains ( "UIKitApplication:" ) &&
71
- logLine . Contains ( "Service exited with abnormal code" ) &&
72
- ( logLine . Contains ( appBundleInfo . AppName ) || logLine . Contains ( appBundleInfo . BundleIdentifier ) ) ;
86
+ // Example line coming from the mlaunch log
87
+ // [07:02:21.6637600] Application 'net.dot.iOS.Simulator.PInvoke.Test' terminated (with exit code '42' and/or crashing signal ').
88
+ private Regex DeviceExitCodeRegex { get ; } = new Regex ( @"terminated \(with exit code '(?<exitCode>-?[0-9]+)' and/or crashing signal" , RegexOptions . Compiled ) ;
89
+
90
+ protected override Match ? IsSignalLine ( AppBundleInformation appBundleInfo , string logLine )
91
+ {
92
+ if ( base . IsSignalLine ( appBundleInfo , logLine ) is Match match && match . Success )
93
+ {
94
+ return match ;
95
+ }
96
+
97
+ if ( logLine . Contains ( appBundleInfo . BundleIdentifier ) )
98
+ {
99
+ return DeviceExitCodeRegex . Match ( logLine ) ;
100
+ }
101
+
102
+ return null ;
103
+ }
73
104
}
74
105
75
106
public class MacCatalystExitCodeDetector : ExitCodeDetector , IMacCatalystExitCodeDetector
76
107
{
77
- // Example line
78
- // Feb 18 06:40:16 Admins-Mac-Mini com.apple.xpc.launchd[1] (net.dot.System.Buffers.Tests.15140[59229]): Service exited with abnormal code: 74
79
- protected override bool IsSignalLine ( AppBundleInformation appBundleInfo , string logLine ) =>
80
- logLine . Contains ( "Service exited with abnormal code" ) &&
81
- ( logLine . Contains ( appBundleInfo . AppName ) || logLine . Contains ( appBundleInfo . BundleIdentifier ) ) ;
82
108
}
0 commit comments