Example #1
0
        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 async Task <ITfsVCWorkspace[]> WorkspacesAsync(bool matchWorkspaceNameOnAnyComputer = false)
        {
            // Build the args.
            var args = new List <string>();

            args.Add("workspaces");
            if (matchWorkspaceNameOnAnyComputer)
            {
                args.Add(WorkspaceName);
                args.Add($"-computer:*");
            }

            args.Add("-format:xml");

            // Run the command.
            TfsVCPorcelainCommandResult result = await TryRunPorcelainCommandAsync(FormatFlags.None, RetriesOnFailure, args.ToArray());

            ArgUtil.NotNull(result, nameof(result));
            if (result.Exception != null)
            {
                // Check if the workspace name was specified and the command returned exit code 1.
                if (matchWorkspaceNameOnAnyComputer && result.Exception.ExitCode == 1)
                {
                    // Ignore the error. This condition can indicate the workspace was not found.
                    return(new ITfsVCWorkspace[0]);
                }

                // Dump the output and throw.
                result.Output?.ForEach(x => ExecutionContext.Output(x ?? string.Empty));
                throw result.Exception;
            }

            // Note, string.join gracefully handles a null element within the IEnumerable<string>.
            string output = string.Join(Environment.NewLine, result.Output ?? new List <string>()) ?? string.Empty;
            string xml    = ExtractXml(output);

            // Deserialize the XML.
            var serializer = new XmlSerializer(typeof(TeeWorkspaces));

            using (var reader = new StringReader(xml))
            {
                return((serializer.Deserialize(reader) as TeeWorkspaces)
                       ?.Workspaces
                       ?.Cast <ITfsVCWorkspace>()
                       .ToArray());
            }
        }
Example #3
0
        protected async Task <string> RunPorcelainCommandAsync(FormatFlags formatFlags, params string[] args)
        {
            // Run the command.
            TfsVCPorcelainCommandResult result = await TryRunPorcelainCommandAsync(formatFlags, args);

            ArgUtil.NotNull(result, nameof(result));
            if (result.Exception != null)
            {
                // The command failed. Dump the output and throw.
                result.Output?.ForEach(x => ExecutionContext.Output(x ?? string.Empty));
                throw result.Exception;
            }

            // Return the output.
            // Note, string.join gracefully handles a null element within the IEnumerable<string>.
            return(string.Join(Environment.NewLine, result.Output ?? new List <string>()));
        }
        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);
            }
        }