Нет описания
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ProcessRunner.cs 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. using System;
  6. using System.Diagnostics;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace Microsoft.Unity.VisualStudio.Editor
  10. {
  11. internal class ProcessRunnerResult
  12. {
  13. public bool Success { get; set; }
  14. public string Output { get; set; }
  15. public string Error { get; set; }
  16. }
  17. internal static class ProcessRunner
  18. {
  19. public const int DefaultTimeoutInMilliseconds = 300000;
  20. public static ProcessStartInfo ProcessStartInfoFor(string filename, string arguments)
  21. {
  22. return new ProcessStartInfo
  23. {
  24. UseShellExecute = false,
  25. CreateNoWindow = true,
  26. RedirectStandardOutput = true,
  27. RedirectStandardError = true,
  28. FileName = filename,
  29. Arguments = arguments
  30. };
  31. }
  32. public static ProcessRunnerResult StartAndWaitForExit(string filename, string arguments, int timeoutms = DefaultTimeoutInMilliseconds, Action<string> onOutputReceived = null)
  33. {
  34. return StartAndWaitForExit(ProcessStartInfoFor(filename, arguments), timeoutms, onOutputReceived);
  35. }
  36. public static ProcessRunnerResult StartAndWaitForExit(ProcessStartInfo processStartInfo, int timeoutms = DefaultTimeoutInMilliseconds, Action<string> onOutputReceived = null)
  37. {
  38. var process = new Process { StartInfo = processStartInfo };
  39. using (process)
  40. {
  41. var sbOutput = new StringBuilder();
  42. var sbError = new StringBuilder();
  43. var outputSource = new TaskCompletionSource<bool>();
  44. var errorSource = new TaskCompletionSource<bool>();
  45. process.OutputDataReceived += (_, e) =>
  46. {
  47. Append(sbOutput, e.Data, outputSource);
  48. if (onOutputReceived != null && e.Data != null)
  49. onOutputReceived(e.Data);
  50. };
  51. process.ErrorDataReceived += (_, e) => Append(sbError, e.Data, errorSource);
  52. process.Start();
  53. process.BeginOutputReadLine();
  54. process.BeginErrorReadLine();
  55. var run = Task.Run(() => process.WaitForExit(timeoutms));
  56. var processTask = Task.WhenAll(run, outputSource.Task, errorSource.Task);
  57. if (Task.WhenAny(Task.Delay(timeoutms), processTask).Result == processTask && run.Result)
  58. return new ProcessRunnerResult {Success = true, Error = sbError.ToString(), Output = sbOutput.ToString()};
  59. try
  60. {
  61. process.Kill();
  62. }
  63. catch
  64. {
  65. /* ignore */
  66. }
  67. return new ProcessRunnerResult {Success = false, Error = sbError.ToString(), Output = sbOutput.ToString()};
  68. }
  69. }
  70. private static void Append(StringBuilder sb, string data, TaskCompletionSource<bool> taskSource)
  71. {
  72. if (data == null)
  73. {
  74. taskSource.SetResult(true);
  75. return;
  76. }
  77. sb?.Append(data);
  78. }
  79. }
  80. }