83 строки
2.6 KiB
Plaintext
83 строки
2.6 KiB
Plaintext
|
#!/usr/bin/env /Library/Frameworks/Mono.framework/Commands/csharp -s
|
||
|
|
||
|
// arguments are: <platform> <outputPath>
|
||
|
|
||
|
using System.Diagnostics;
|
||
|
using System.IO;
|
||
|
using System.Threading;
|
||
|
using System.Xml;
|
||
|
|
||
|
var args = Environment.GetCommandLineArgs ();
|
||
|
var initialArgumentCount = 3;
|
||
|
if (args.Length <= initialArgumentCount + 1 /* 3 default arguments (executable + script + -s) */) {
|
||
|
// first arg is "/Library/Frameworks/Mono.framework/Versions/4.8.0/lib/mono/4.5/csharp.exe"
|
||
|
// second arg the script itself
|
||
|
// third argument is -s
|
||
|
// then comes the ones we care about
|
||
|
Console.WriteLine ($"Need two arguments (the timeout + the command to launch), got {args.Length - initialArgumentCount} argument(s)");
|
||
|
Environment.Exit (1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var launchTimeout = TimeSpan.FromSeconds (10); // must launch within a few seconds.
|
||
|
var argIndex = initialArgumentCount;
|
||
|
var executionTimeout = TimeSpan.FromSeconds (int.Parse (args [argIndex++]));
|
||
|
var commands = args.Skip (argIndex).ToArray ();
|
||
|
|
||
|
var pid = Process.GetCurrentProcess ().Id;
|
||
|
var maxLaunchAttempts = 10;
|
||
|
var exitCode = -1;
|
||
|
for (var attempt = 0; attempt < maxLaunchAttempts; attempt++) {
|
||
|
var launchTimeoutFile = Path.GetFullPath ($"launch-timeout-sentinel-{pid}-{attempt}.txt");
|
||
|
var launchTimedOut = new ManualResetEvent (false);
|
||
|
var p = new Process ();
|
||
|
|
||
|
var launchTimer = new Thread (() => {
|
||
|
if (p.WaitForExit ((int) launchTimeout.TotalMilliseconds)) {
|
||
|
Console.WriteLine ($"App finished before launch timeout triggered.");
|
||
|
} else if (!File.Exists (launchTimeoutFile)) {
|
||
|
Console.WriteLine ($"Launch timed out after {launchTimeout.TotalSeconds} seconds.");
|
||
|
launchTimedOut.Set ();
|
||
|
p.Kill ();
|
||
|
}
|
||
|
}) {
|
||
|
IsBackground = true,
|
||
|
};
|
||
|
|
||
|
try {
|
||
|
p.StartInfo.FileName = commands [0];
|
||
|
p.StartInfo.Arguments = string.Join (" ", commands.Skip (1));
|
||
|
p.StartInfo.UseShellExecute = false;
|
||
|
p.StartInfo.EnvironmentVariables ["LAUNCH_SENTINEL_FILE"] = launchTimeoutFile;
|
||
|
|
||
|
Console.WriteLine ($"Launching (attempt #{attempt + 1}):");
|
||
|
Console.WriteLine ($" {p.StartInfo.FileName} {p.StartInfo.Arguments}");
|
||
|
|
||
|
p.Start ();
|
||
|
|
||
|
launchTimer.Start ();
|
||
|
|
||
|
if (!p.WaitForExit ((int) executionTimeout.TotalMilliseconds)) {
|
||
|
Console.WriteLine ($"Execution timed out after {executionTimeout.TotalSeconds} seconds.");
|
||
|
p.Kill ();
|
||
|
p.WaitForExit ();
|
||
|
}
|
||
|
|
||
|
launchTimer.Join ();
|
||
|
|
||
|
exitCode = p.ExitCode;
|
||
|
|
||
|
if (launchTimedOut.WaitOne (0)) {
|
||
|
Console.WriteLine ($"Launching again since the launch timeout triggered.");
|
||
|
continue;
|
||
|
}
|
||
|
Console.WriteLine ($"Execution completed with exit code {exitCode}");
|
||
|
} finally {
|
||
|
File.Delete (launchTimeoutFile);
|
||
|
p.Dispose ();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Environment.Exit (exitCode);
|