public async Task TestCancel() { const int SecondsToRun = 20; using (TestHostContext hc = new TestHostContext(this)) using (var tokenSource = new CancellationTokenSource()) { Tracing trace = hc.GetTrace(); var processInvoker = new ProcessInvoker(); processInvoker.Initialize(hc); Stopwatch watch = Stopwatch.StartNew(); #if OS_WINDOWS Task execTask = processInvoker.ExecuteAsync("", "cmd.exe", $"/c \"choice /T {SecondsToRun} /D y\"", null, tokenSource.Token); #endif #if (OS_OSX || OS_LINUX) Task execTask = processInvoker.ExecuteAsync("", "bash", $"-c \"sleep {SecondsToRun}s\"", null, tokenSource.Token); #endif tokenSource.Cancel(); await Task.WhenAny(new Task[] { execTask }); Assert.True(execTask.IsCompleted); Assert.True(!execTask.IsFaulted); Assert.True(execTask.IsCanceled); watch.Stop(); var elapsedSeconds = watch.ElapsedMilliseconds / 1000; //if cancellation fails, then execution time is more than 10 seconds Assert.True(elapsedSeconds < SecondsToRun / 2, "cancellation failed, because task took too long to run"); } }
public async Task TestCancel() { const int SecondsToRun = 20; using (TestHostContext hc = new TestHostContext(this)) using (var tokenSource = new CancellationTokenSource()) { Tracing trace = hc.GetTrace(); var processInvoker = new ProcessInvoker(); processInvoker.Initialize(hc); Stopwatch watch = Stopwatch.StartNew(); #if OS_WINDOWS Task execTask = processInvoker.ExecuteAsync("", "cmd.exe", $"/c \"choice /T {SecondsToRun} /D y\"", null, tokenSource.Token); #endif #if (OS_OSX || OS_LINUX) Task execTask = processInvoker.ExecuteAsync("", "bash", $"-c \"sleep {SecondsToRun}s\"", null, tokenSource.Token); #endif await Task.Delay(500); tokenSource.Cancel(); await Task.WhenAny(execTask); Assert.True(execTask.IsCompleted); Assert.True(!execTask.IsFaulted); Assert.True(execTask.IsCanceled); watch.Stop(); var elapsedSeconds = watch.ElapsedMilliseconds / 1000; //if cancellation fails, then execution time is more than 10 seconds Assert.True(elapsedSeconds < SecondsToRun / 2, $"cancellation failed, because task took too long to run. {elapsedSeconds}"); } }
private async Task RunCommandAsync(params string[] args) { // Validation. ArgUtil.NotNull(args, nameof(args)); ArgUtil.NotNull(_context, nameof(_context)); // Invoke tf. var processInvoker = new ProcessInvoker(_context); var outputLock = new object(); processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { _context.Output(e.Data); } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { _context.Output(e.Data); } }; string arguments = FormatArgumentsWithDefaults(args); _context.Command($@"{_svn} {arguments}"); await processInvoker.ExecuteAsync( workingDirectory : _context.Variables.GetValueOrDefault("agent.workfolder")?.Value, fileName : _svn, arguments : arguments, environment : null, requireExitCodeZero : true, cancellationToken : _cancellationToken); }
private async Task <int> ExecuteGitCommandAsync(AgentTaskPluginExecutionContext context, string repoRoot, string command, string options, IList <string> output) { string arg = StringUtil.Format($"{command} {options}").Trim(); context.Command($"git {arg}"); if (output == null) { output = new List <string>(); } var processInvoker = new ProcessInvoker(context); processInvoker.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs message) { output.Add(message.Data); }; processInvoker.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs message) { context.Output(message.Data); }; return(await processInvoker.ExecuteAsync( workingDirectory : repoRoot, fileName : gitPath, arguments : arg, environment : gitEnv, requireExitCodeZero : false, outputEncoding : s_encoding, cancellationToken : default(CancellationToken))); }
public async Task <int> ExecuteAsync( string workingDirectory, string fileName, string arguments, IDictionary <string, string> environment, bool requireExitCodeZero, Encoding outputEncoding, bool killProcessOnCancel, Channel <string> redirectStandardIn, bool inheritConsoleHandler, bool keepStandardInOpen, bool highPriorityProcess, CancellationToken cancellationToken) { _invoker.ErrorDataReceived += this.ErrorDataReceived; _invoker.OutputDataReceived += this.OutputDataReceived; return(await _invoker.ExecuteAsync( workingDirectory, fileName, arguments, environment, requireExitCodeZero, outputEncoding, killProcessOnCancel, redirectStandardIn, inheritConsoleHandler, keepStandardInOpen, highPriorityProcess, cancellationToken)); }
private async Task <int> ExecuteGitCommandAsync(AgentTaskPluginExecutionContext context, string repoRoot, string command, string options, string additionalCommandLine, CancellationToken cancellationToken) { string arg = StringUtil.Format($"{additionalCommandLine} {command} {options}").Trim(); context.Command($"git {arg}"); var processInvoker = new ProcessInvoker(context); processInvoker.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs message) { context.Output(message.Data); }; processInvoker.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs message) { context.Output(message.Data); }; return(await processInvoker.ExecuteAsync( workingDirectory : repoRoot, fileName : gitPath, arguments : arg, environment : GetGitEnvironmentVariables(context), requireExitCodeZero : false, outputEncoding : s_encoding, cancellationToken : cancellationToken)); }
private async Task <FileSharePublishResult> PublishArtifactUsingRobocopyAsync( AgentTaskPluginExecutionContext executionContext, string dropLocation, string downloadFolderPath, int parallelCount, CancellationToken cancellationToken) { executionContext.Output(StringUtil.Loc("PublishingArtifactUsingRobocopy")); using (var processInvoker = new ProcessInvoker(this.context)) { // Save STDOUT from worker, worker will use STDOUT report unhandle exception. processInvoker.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stdout) { if (!string.IsNullOrEmpty(stdout.Data)) { executionContext.Output(stdout.Data); } }; // Save STDERR from worker, worker will use STDERR on crash. processInvoker.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stderr) { if (!string.IsNullOrEmpty(stderr.Data)) { executionContext.Error(stderr.Data); } }; var trimChars = new[] { '\\', '/' }; dropLocation = Path.Combine(dropLocation.TrimEnd(trimChars)); downloadFolderPath = downloadFolderPath.TrimEnd(trimChars); string robocopyArguments = "\"" + dropLocation + "\" \"" + downloadFolderPath + "\" * /E /COPY:DA /NP /R:3"; robocopyArguments += " /MT:" + parallelCount; int exitCode = await processInvoker.ExecuteAsync( workingDirectory : "", fileName : "robocopy", arguments : robocopyArguments, environment : null, requireExitCodeZero : false, outputEncoding : null, killProcessOnCancel : true, cancellationToken : cancellationToken); executionContext.Output(StringUtil.Loc("RobocopyBasedPublishArtifactTaskExitCode", exitCode)); // Exit code returned from robocopy. For more info https://blogs.technet.microsoft.com/deploymentguys/2008/06/16/robocopy-exit-codes/ if (exitCode >= 8) { throw new Exception(StringUtil.Loc("RobocopyBasedPublishArtifactTaskFailed", exitCode)); } return(new FileSharePublishResult(exitCode)); } }
public async Task SuccessExitsWithCodeZero() { using (TestHostContext hc = new TestHostContext(this)) { Tracing trace = hc.GetTrace(); Int32 exitCode = -1; var processInvoker = new ProcessInvoker(); processInvoker.Initialize(hc); #if OS_WINDOWS exitCode = await processInvoker.ExecuteAsync("", "cmd.exe", "/c \"dir >nul\"", null, CancellationToken.None); #endif #if (OS_OSX || OS_LINUX) exitCode = await processInvoker.ExecuteAsync("", "bash", "-c echo .", null, CancellationToken.None); #endif trace.Info("Exit Code: {0}", exitCode); Assert.Equal(0, exitCode); } }
public async Task SuccessExitsWithCodeZero() { using (TestHostContext hc = new TestHostContext(this)) using (var tokenSource = new CancellationTokenSource()) { Tracing trace = hc.GetTrace(); Int32 exitCode = -1; var processInvoker = new ProcessInvoker(); processInvoker.Initialize(hc); #if OS_WINDOWS exitCode = await processInvoker.ExecuteAsync("", "cmd.exe", "/c \"dir >nul\"", null, tokenSource.Token); #endif #if (OS_OSX || OS_LINUX) exitCode = await processInvoker.ExecuteAsync("", "bash", "-c echo .", null, tokenSource.Token); #endif trace.Info("Exit Code: {0}", exitCode); Assert.Equal(0, exitCode); } }
private async Task <string> RunPorcelainCommandAsync(params string[] args) { // Validation. ArgUtil.NotNull(args, nameof(args)); ArgUtil.NotNull(_context, nameof(_context)); // Invoke tf. var processInvoker = new ProcessInvoker(_context); var output = new List <string>(); var outputLock = new object(); processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { _context.Debug(e.Data); output.Add(e.Data); } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { _context.Debug(e.Data); output.Add(e.Data); } }; string arguments = FormatArgumentsWithDefaults(args); _context.Debug($@"{_svn} {arguments}"); // TODO: Test whether the output encoding needs to be specified on a non-Latin OS. try { await processInvoker.ExecuteAsync( workingDirectory : _context.Variables.GetValueOrDefault("agent.workfolder")?.Value, fileName : _svn, arguments : arguments, environment : null, requireExitCodeZero : true, cancellationToken : _cancellationToken); } catch (ProcessExitCodeException) { // The command failed. Dump the output and throw. output.ForEach(x => _context.Output(x ?? string.Empty)); throw; } // Note, string.join gracefully handles a null element within the IEnumerable<string>. return(string.Join(Environment.NewLine, output)); }
protected async Task <TfsVCPorcelainCommandResult> TryRunPorcelainCommandAsync(FormatFlags formatFlags, params string[] args) { // Validation. ArgUtil.NotNull(args, nameof(args)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); // Invoke tf. var processInvoker = new ProcessInvoker(ExecutionContext); var result = new TfsVCPorcelainCommandResult(); var outputLock = new object(); processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { ExecutionContext.Debug(e.Data); result.Output.Add(e.Data); } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { ExecutionContext.Debug(e.Data); result.Output.Add(e.Data); } }; string arguments = FormatArguments(formatFlags, args); ExecutionContext.Debug($@"tf {arguments}"); // TODO: Test whether the output encoding needs to be specified on a non-Latin OS. try { await processInvoker.ExecuteAsync( workingDirectory : SourcesDirectory, fileName : "tf", arguments : arguments, environment : AdditionalEnvironmentVariables, requireExitCodeZero : true, outputEncoding : OutputEncoding, cancellationToken : CancellationToken); } catch (ProcessExitCodeException ex) { result.Exception = ex; } return(result); }
public void SetupClientCertificate(string clientCert, string clientCertKey, string clientCertArchive, string clientCertPassword) { ExecutionContext.Debug("Convert client certificate from 'pkcs' format to 'jks' format."); string toolPath = WhichUtil.Which("keytool", true, ExecutionContext); string jksFile = Path.Combine(ExecutionContext.Variables.GetValueOrDefault("agent.tempdirectory")?.Value, $"{Guid.NewGuid()}.jks"); string argLine; if (!string.IsNullOrEmpty(clientCertPassword)) { argLine = $"-importkeystore -srckeystore \"{clientCertArchive}\" -srcstoretype pkcs12 -destkeystore \"{jksFile}\" -deststoretype JKS -srcstorepass \"{clientCertPassword}\" -deststorepass \"{clientCertPassword}\""; } else { argLine = $"-importkeystore -srckeystore \"{clientCertArchive}\" -srcstoretype pkcs12 -destkeystore \"{jksFile}\" -deststoretype JKS"; } ExecutionContext.Command($"{toolPath} {argLine}"); using (var processInvoker = new ProcessInvoker(ExecutionContext)) { processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs args) => { if (!string.IsNullOrEmpty(args.Data)) { ExecutionContext.Output(args.Data); } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs args) => { if (!string.IsNullOrEmpty(args.Data)) { ExecutionContext.Output(args.Data); } }; processInvoker.ExecuteAsync(ExecutionContext.Variables.GetValueOrDefault("system.defaultworkingdirectory")?.Value, toolPath, argLine, null, true, CancellationToken.None).GetAwaiter().GetResult(); if (!string.IsNullOrEmpty(clientCertPassword)) { ExecutionContext.Debug($"Set TF_ADDITIONAL_JAVA_ARGS=-Djavax.net.ssl.keyStore={jksFile} -Djavax.net.ssl.keyStorePassword={clientCertPassword}"); AdditionalEnvironmentVariables["TF_ADDITIONAL_JAVA_ARGS"] = $"-Djavax.net.ssl.keyStore={jksFile} -Djavax.net.ssl.keyStorePassword={clientCertPassword}"; } else { ExecutionContext.Debug($"Set TF_ADDITIONAL_JAVA_ARGS=-Djavax.net.ssl.keyStore={jksFile}"); AdditionalEnvironmentVariables["TF_ADDITIONAL_JAVA_ARGS"] = $"-Djavax.net.ssl.keyStore={jksFile}"; } } }
private async Task CreateRepository(TestHostContext hostConetxt, string path, string url) { Directory.CreateDirectory(path); var gitPath = WhichUtil.Which("git", true); var environment = new Dictionary <string, string>(); using (var processInvoker = new ProcessInvoker(hostConetxt.GetTrace())) { await processInvoker.ExecuteAsync(path, gitPath, "init", environment, CancellationToken.None); } using (var processInvoker = new ProcessInvoker(hostConetxt.GetTrace())) { await processInvoker.ExecuteAsync(path, gitPath, $"remote add origin {url}", environment, CancellationToken.None); } }
protected async Task <int> RunCommandAsync(FormatFlags formatFlags, bool quiet, bool failOnNonZeroExitCode, params string[] args) { // Validation. ArgUtil.NotNull(args, nameof(args)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); // Invoke tf. using (var processInvoker = new ProcessInvoker(ExecutionContext)) { var outputLock = new object(); processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { if (quiet) { ExecutionContext.Debug(e.Data); } else { ExecutionContext.Output(e.Data); } } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { ExecutionContext.Output(e.Data); } }; string arguments = FormatArguments(formatFlags, args); ExecutionContext.Command($@"tf {arguments}"); return(await processInvoker.ExecuteAsync( workingDirectory : SourcesDirectory, fileName : "tf", arguments : arguments, environment : AdditionalEnvironmentVariables, requireExitCodeZero : failOnNonZeroExitCode, outputEncoding : OutputEncoding, cancellationToken : CancellationToken)); } }
public async Task DefaultsToCurrentSystemOemEncoding() { // This test verifies that the additional code pages encoding provider is registered. // By default, only Unicode encodings, ASCII, and code page 28591 are supported. An // additional provider must be registered to support the full set of encodings that // were included in Full .NET prior to 4.6. // // For example, on an en-US box, this is required for loading the encoding for the // default console output code page '437'. Without loading the correct encoding for // code page IBM437, some characters cannot be translated correctly, e.g. write 'ç' // from powershell.exe. using (TestHostContext hc = new TestHostContext(this)) { Tracing trace = hc.GetTrace(); var processInvoker = new ProcessInvoker(); processInvoker.Initialize(hc); var stdout = new List <string>(); var stderr = new List <string>(); processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { stdout.Add(e.Data); }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { stderr.Add(e.Data); }; await processInvoker.ExecuteAsync( workingDirectory : "", fileName : "powershell.exe", arguments : $@"-NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ""Write-Host 'From STDOUT ''ç''' ; Write-Error 'From STDERR ''ç'''""", environment : null, requireExitCodeZero : false, cancellationToken : CancellationToken.None); Assert.Equal(1, stdout.Count); Assert.Equal("From STDOUT 'ç'", stdout[0]); Assert.True(stderr.Count > 0); Assert.True(stderr[0].Contains("From STDERR 'ç'")); } }
private static async Task CreateDirectoryReparsePoint(IHostContext context, string link, string target) { #if OS_WINDOWS string fileName = Environment.GetEnvironmentVariable("ComSpec"); string arguments = $@"/c ""mklink /J ""{link}"" {target}"""""; #else string fileName = "/bin/ln"; string arguments = $@"-s ""{target}"" ""{link}"""; #endif ArgUtil.File(fileName, nameof(fileName)); using (var processInvoker = new ProcessInvoker()) { processInvoker.Initialize(context); await processInvoker.ExecuteAsync( workingDirectory : context.GetDirectory(WellKnownDirectory.Bin), fileName : fileName, arguments : arguments, environment : null, requireExitCodeZero : true, cancellationToken : CancellationToken.None); } }
protected async Task RunCommandAsync(FormatFlags formatFlags, params string[] args) { // Validation. PluginUtil.NotNull(args, nameof(args)); PluginUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); // Invoke tf. var processInvoker = new ProcessInvoker(ExecutionContext); var outputLock = new object(); processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { ExecutionContext.Output(e.Data); } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { ExecutionContext.Output(e.Data); } }; string arguments = FormatArguments(formatFlags, args); ExecutionContext.Command($@"tf {arguments}"); await processInvoker.ExecuteAsync( workingDirectory : SourcesDirectory, fileName : "tf", arguments : arguments, environment : AdditionalEnvironmentVariables, requireExitCodeZero : true, outputEncoding : OutputEncoding, cancellationToken : CancellationToken); }
protected sealed override Object EvaluateCore( EvaluationContext context, out ResultMemory resultMemory) { resultMemory = null; var templateContext = context.State as DistributedTask.ObjectTemplating.TemplateContext; ArgUtil.NotNull(templateContext, nameof(templateContext)); templateContext.ExpressionValues.TryGetValue(PipelineTemplateConstants.GitHub, out var githubContextData); ArgUtil.NotNull(githubContextData, nameof(githubContextData)); var githubContext = githubContextData as DictionaryContextData; ArgUtil.NotNull(githubContext, nameof(githubContext)); githubContext.TryGetValue(PipelineTemplateConstants.Workspace, out var workspace); var workspaceData = workspace as StringContextData; ArgUtil.NotNull(workspaceData, nameof(workspaceData)); string githubWorkspace = workspaceData.Value; bool followSymlink = false; List <string> patterns = new List <string>(); var firstParameter = true; foreach (var parameter in Parameters) { var parameterString = parameter.Evaluate(context).ConvertToString(); if (firstParameter) { firstParameter = false; if (parameterString.StartsWith("--")) { if (string.Equals(parameterString, "--follow-symbolic-links", StringComparison.OrdinalIgnoreCase)) { followSymlink = true; continue; } else { throw new ArgumentOutOfRangeException($"Invalid glob option {parameterString}, avaliable option: '--follow-symbolic-links'."); } } } patterns.Add(parameterString); } context.Trace.Info($"Search root directory: '{githubWorkspace}'"); context.Trace.Info($"Search pattern: '{string.Join(", ", patterns)}'"); string binDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); string runnerRoot = new DirectoryInfo(binDir).Parent.FullName; string node = Path.Combine(runnerRoot, "externals", "node12", "bin", $"node{IOUtil.ExeExtension}"); string hashFilesScript = Path.Combine(binDir, "hashFiles"); var hashResult = string.Empty; var p = new ProcessInvoker(new HashFilesTrace(context.Trace)); p.ErrorDataReceived += ((_, data) => { if (!string.IsNullOrEmpty(data.Data) && data.Data.StartsWith("__OUTPUT__") && data.Data.EndsWith("__OUTPUT__")) { hashResult = data.Data.Substring(10, data.Data.Length - 20); context.Trace.Info($"Hash result: '{hashResult}'"); } else { context.Trace.Info(data.Data); } }); p.OutputDataReceived += ((_, data) => { context.Trace.Info(data.Data); }); var env = new Dictionary <string, string>(); if (followSymlink) { env["followSymbolicLinks"] = "true"; } env["patterns"] = string.Join(Environment.NewLine, patterns); int exitCode = p.ExecuteAsync(workingDirectory: githubWorkspace, fileName: node, arguments: $"\"{hashFilesScript.Replace("\"", "\\\"")}\"", environment: env, requireExitCodeZero: false, cancellationToken: new CancellationTokenSource(TimeSpan.FromSeconds(120)).Token).GetAwaiter().GetResult(); if (exitCode != 0) { throw new InvalidOperationException($"hashFiles('{ExpressionUtility.StringEscape(string.Join(", ", patterns))}') failed. Fail to hash files under directory '{githubWorkspace}'"); } return(hashResult); }
protected async Task <TfsVCPorcelainCommandResult> TryRunPorcelainCommandAsync(FormatFlags formatFlags, int retriesOnFailure, params string[] args) { // Validation. ArgUtil.NotNull(args, nameof(args)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); // Invoke tf. using (var processInvoker = new ProcessInvoker(ExecutionContext)) { var result = new TfsVCPorcelainCommandResult(); var outputLock = new object(); processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { ExecutionContext.Debug(e.Data); result.Output.Add(e.Data); } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { ExecutionContext.Debug(e.Data); result.Output.Add(e.Data); } }; string arguments = FormatArguments(formatFlags, args); ExecutionContext.Debug($@"tf {arguments}"); // TODO: Test whether the output encoding needs to be specified on a non-Latin OS. try { for (int attempt = 0; attempt < retriesOnFailure; attempt++) { int exitCode = await processInvoker.ExecuteAsync( workingDirectory : SourcesDirectory, fileName : "tf", arguments : arguments, environment : AdditionalEnvironmentVariables, requireExitCodeZero : false, outputEncoding : OutputEncoding, cancellationToken : CancellationToken); if (exitCode == 0) { return(result); } int sleep = Math.Min(200 * (int)Math.Pow(5, attempt), 30000); ExecutionContext.Output($"Sleeping for {sleep} ms"); Thread.Sleep(sleep); // Use attempt+2 since we're using 0 based indexing and we're displaying this for the next attempt. ExecutionContext.Output($@"Retrying. Attempt ${attempt + 2}/${retriesOnFailure}"); } // Perform one last try and fail on non-zero exit code await processInvoker.ExecuteAsync( workingDirectory : SourcesDirectory, fileName : "tf", arguments : arguments, environment : AdditionalEnvironmentVariables, requireExitCodeZero : true, outputEncoding : OutputEncoding, cancellationToken : CancellationToken); } catch (ProcessExitCodeException ex) { result.Exception = ex; } return(result); } }
protected async Task RunCommandAsync(FormatFlags formatFlags, bool quiet, int retriesOnFailure, params string[] args) { // Validation. ArgUtil.NotNull(args, nameof(args)); ArgUtil.NotNull(ExecutionContext, nameof(ExecutionContext)); // Invoke tf. using (var processInvoker = new ProcessInvoker(ExecutionContext)) { var outputLock = new object(); processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { if (quiet) { ExecutionContext.Debug(e.Data); } else { ExecutionContext.Output(e.Data); } } }; processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) => { lock (outputLock) { ExecutionContext.Output(e.Data); } }; string arguments = FormatArguments(formatFlags, args); ExecutionContext.Command($@"tf {arguments}"); for (int attempt = 0; attempt < retriesOnFailure; attempt++) { int exitCode = await processInvoker.ExecuteAsync( workingDirectory : SourcesDirectory, fileName : "tf", arguments : arguments, environment : AdditionalEnvironmentVariables, requireExitCodeZero : false, outputEncoding : OutputEncoding, cancellationToken : CancellationToken); if (exitCode == 0) { return; } int sleep = Math.Min(200 * (int)Math.Pow(5, attempt), 30000); ExecutionContext.Output($"Sleeping for {sleep} ms"); await Task.Delay(sleep); // Use attempt+2 since we're using 0 based indexing and we're displaying this for the next attempt. ExecutionContext.Output($@"Retrying. Attempt ${attempt+2}/${retriesOnFailure}"); } // Perform one last try and fail on non-zero exit code await processInvoker.ExecuteAsync( workingDirectory : SourcesDirectory, fileName : "tf", arguments : arguments, environment : AdditionalEnvironmentVariables, requireExitCodeZero : true, outputEncoding : OutputEncoding, cancellationToken : CancellationToken); } }
private static async Task CreateDirectoryReparsePoint(IHostContext context, string link, string target) { #if OS_WINDOWS string fileName = Environment.GetEnvironmentVariable("ComSpec"); string arguments = $@"/c ""mklink /J ""{link}"" {target}"""""; #else string fileName = "/bin/ln"; string arguments = $@"-s ""{target}"" ""{link}"""; #endif ArgUtil.File(fileName, nameof(fileName)); using (var processInvoker = new ProcessInvoker()) { processInvoker.Initialize(context); await processInvoker.ExecuteAsync( workingDirectory: IOUtil.GetBinPath(), fileName: fileName, arguments: arguments, environment: null, requireExitCodeZero: true, cancellationToken: CancellationToken.None); } }