PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/Kudu.Core/Commands/CommandExecutor.cs

https://github.com/moacap/kudu
C# | 163 lines | 139 code | 22 blank | 2 comment | 14 complexity | f4b31f0f27428a23a07e312b9891d49c MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.IO.Abstractions;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using Kudu.Core.Infrastructure;
  10. namespace Kudu.Core.Commands
  11. {
  12. public class CommandExecutor : ICommandExecutor
  13. {
  14. private readonly string _workingDirectory;
  15. private Process _executingProcess;
  16. public CommandExecutor(string workingDirectory)
  17. {
  18. _workingDirectory = workingDirectory;
  19. }
  20. public event Action<CommandEvent> CommandEvent;
  21. public CommandResult ExecuteCommand(string command)
  22. {
  23. var result = new CommandResult();
  24. int exitCode = 0;
  25. var outputBuilder = new StringBuilder();
  26. var errorBuilder = new StringBuilder();
  27. Action<CommandEvent> handler = args =>
  28. {
  29. switch (args.EventType)
  30. {
  31. case CommandEventType.Output:
  32. outputBuilder.AppendLine(args.Data);
  33. break;
  34. case CommandEventType.Error:
  35. errorBuilder.AppendLine(args.Data);
  36. break;
  37. case CommandEventType.Complete:
  38. exitCode = args.ExitCode;
  39. break;
  40. default:
  41. break;
  42. }
  43. };
  44. try
  45. {
  46. // Code reuse is good
  47. CommandEvent += handler;
  48. ExecuteCommandAsync(command);
  49. }
  50. finally
  51. {
  52. CommandEvent -= handler;
  53. }
  54. _executingProcess.WaitForExit();
  55. result.Output = outputBuilder.ToString();
  56. result.Error = errorBuilder.ToString();
  57. result.ExitCode = exitCode;
  58. return result;
  59. }
  60. public void ExecuteCommandAsync(string command)
  61. {
  62. string path = _workingDirectory;
  63. _executingProcess = new Process();
  64. _executingProcess.StartInfo.FileName = "cmd";
  65. _executingProcess.StartInfo.WorkingDirectory = path;
  66. _executingProcess.StartInfo.Arguments = "/c " + command;
  67. _executingProcess.StartInfo.CreateNoWindow = true;
  68. _executingProcess.StartInfo.UseShellExecute = false;
  69. _executingProcess.StartInfo.RedirectStandardInput = true;
  70. _executingProcess.StartInfo.RedirectStandardOutput = true;
  71. _executingProcess.StartInfo.RedirectStandardError = true;
  72. _executingProcess.StartInfo.StandardOutputEncoding = Encoding.UTF8;
  73. _executingProcess.StartInfo.StandardErrorEncoding = Encoding.UTF8;
  74. _executingProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  75. _executingProcess.StartInfo.ErrorDialog = false;
  76. var pathEnv = _executingProcess.StartInfo.EnvironmentVariables["PATH"];
  77. if (!pathEnv.EndsWith(";"))
  78. {
  79. pathEnv += ";";
  80. }
  81. pathEnv += Path.GetDirectoryName(PathUtility.ResolveGitPath());
  82. pathEnv += ";";
  83. pathEnv += Path.GetDirectoryName(PathUtility.ResolveMSBuildPath());
  84. _executingProcess.StartInfo.EnvironmentVariables["PATH"] = pathEnv;
  85. var commandEvent = CommandEvent;
  86. _executingProcess.Exited += (sender, e) =>
  87. {
  88. if (commandEvent != null)
  89. {
  90. commandEvent(new CommandEvent(CommandEventType.Complete)
  91. {
  92. ExitCode = _executingProcess.ExitCode
  93. });
  94. }
  95. };
  96. _executingProcess.OutputDataReceived += (sender, e) =>
  97. {
  98. if (e.Data == null)
  99. {
  100. return;
  101. }
  102. if (commandEvent != null)
  103. {
  104. commandEvent(new CommandEvent(CommandEventType.Output, e.Data));
  105. }
  106. };
  107. _executingProcess.ErrorDataReceived += (sender, e) =>
  108. {
  109. if (e.Data == null)
  110. {
  111. return;
  112. }
  113. if (commandEvent != null)
  114. {
  115. commandEvent(new CommandEvent(CommandEventType.Error, e.Data));
  116. }
  117. };
  118. _executingProcess.EnableRaisingEvents = true;
  119. _executingProcess.Start();
  120. _executingProcess.BeginErrorReadLine();
  121. _executingProcess.BeginOutputReadLine();
  122. _executingProcess.StandardInput.Close();
  123. }
  124. public void CancelCommand()
  125. {
  126. try
  127. {
  128. if (_executingProcess != null)
  129. {
  130. _executingProcess.CancelErrorRead();
  131. _executingProcess.CancelOutputRead();
  132. _executingProcess.Kill();
  133. }
  134. }
  135. catch
  136. {
  137. // Swallow the exception, we don't care the if process can't be killed
  138. }
  139. }
  140. }
  141. }