コード例 #1
0
        public static void DeleteDirectory(string path, bool contentsOnly, bool continueOnContentDeleteError, CancellationToken cancellationToken)
        {
            ArgUtil.NotNullOrEmpty(path, nameof(path));
            DirectoryInfo directory = new DirectoryInfo(path);

            if (!directory.Exists)
            {
                return;
            }

            if (!contentsOnly)
            {
                // Remove the readonly flag.
                RemoveReadOnly(directory);

                // Check if the directory is a reparse point.
                if (directory.Attributes.HasFlag(FileAttributes.ReparsePoint))
                {
                    // Delete the reparse point directory and short-circuit.
                    directory.Delete();
                    return;
                }
            }

            // Initialize a concurrent stack to store the directories. The directories
            // cannot be deleted until the files are deleted.
            var directories = new ConcurrentStack <DirectoryInfo>();

            if (!contentsOnly)
            {
                directories.Push(directory);
            }

            // Create a new token source for the parallel query. The parallel query should be
            // canceled after the first error is encountered. Otherwise the number of exceptions
            // could get out of control for a large directory with access denied on every file.
            using (var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
            {
                try
                {
                    // Recursively delete all files and store all subdirectories.
                    Enumerate(directory, tokenSource)
                    .AsParallel()
                    .WithCancellation(tokenSource.Token)
                    .ForAll((FileSystemInfo item) =>
                    {
                        bool success = false;
                        try
                        {
                            // Remove the readonly attribute.
                            RemoveReadOnly(item);

                            // Check if the item is a file.
                            if (item is FileInfo)
                            {
                                // Delete the file.
                                item.Delete();
                            }
                            else
                            {
                                // Check if the item is a directory reparse point.
                                var subdirectory = item as DirectoryInfo;
                                ArgUtil.NotNull(subdirectory, nameof(subdirectory));
                                if (subdirectory.Attributes.HasFlag(FileAttributes.ReparsePoint))
                                {
                                    try
                                    {
                                        // Delete the reparse point.
                                        subdirectory.Delete();
                                    }
                                    catch (DirectoryNotFoundException)
                                    {
                                        // The target of the reparse point directory has been deleted.
                                        // Therefore the item is no longer a directory and is now a file.
                                        //
                                        // Deletion of reparse point directories happens in parallel. This case can occur
                                        // when reparse point directory FOO points to some other reparse point directory BAR,
                                        // and BAR is deleted after the DirectoryInfo for FOO has already been initialized.
                                        File.Delete(subdirectory.FullName);
                                    }
                                }
                                else
                                {
                                    // Store the directory.
                                    directories.Push(subdirectory);
                                }
                            }

                            success = true;
                        }
                        catch (Exception) when(continueOnContentDeleteError)
                        {
                            // ignore any exception when continueOnContentDeleteError is true.
                            success = true;
                        }
                        finally
                        {
                            if (!success)
                            {
                                tokenSource.Cancel();     // Cancel is thread-safe.
                            }
                        }
                    });
                }
                catch (Exception)
                {
                    tokenSource.Cancel();
                    throw;
                }
            }

            // Delete the directories.
            foreach (DirectoryInfo dir in directories.OrderByDescending(x => x.FullName.Length))
            {
                cancellationToken.ThrowIfCancellationRequested();
                dir.Delete();
            }
        }
コード例 #2
0
        public static string Which(string command, bool require = false, ITraceWriter trace = null)
        {
            ArgUtil.NotNullOrEmpty(command, nameof(command));
            trace?.Info($"Which: '{command}'");
            string path = Environment.GetEnvironmentVariable(PathUtil.PathVariable);

            if (string.IsNullOrEmpty(path))
            {
                trace?.Info("PATH environment variable not defined.");
                path = path ?? string.Empty;
            }

            string[] pathSegments = path.Split(new Char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < pathSegments.Length; i++)
            {
                pathSegments[i] = Environment.ExpandEnvironmentVariables(pathSegments[i]);
            }

            foreach (string pathSegment in pathSegments)
            {
                if (!string.IsNullOrEmpty(pathSegment) && Directory.Exists(pathSegment))
                {
                    string[] matches = null;
#if OS_WINDOWS
                    string pathExt = Environment.GetEnvironmentVariable("PATHEXT");
                    if (string.IsNullOrEmpty(pathExt))
                    {
                        // XP's system default value for PATHEXT system variable
                        pathExt = ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh";
                    }

                    string[] pathExtSegments = pathExt.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);

                    // if command already has an extension.
                    if (pathExtSegments.Any(ext => command.EndsWith(ext, StringComparison.OrdinalIgnoreCase)))
                    {
                        try
                        {
                            matches = Directory.GetFiles(pathSegment, command);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            trace?.Info("Ignore UnauthorizedAccess exception during Which.");
                            trace?.Verbose(ex.ToString());
                        }

                        if (matches != null && matches.Length > 0)
                        {
                            trace?.Info($"Location: '{matches.First()}'");
                            return(matches.First());
                        }
                    }
                    else
                    {
                        string searchPattern;
                        searchPattern = StringUtil.Format($"{command}.*");
                        try
                        {
                            matches = Directory.GetFiles(pathSegment, searchPattern);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            trace?.Info("Ignore UnauthorizedAccess exception during Which.");
                            trace?.Verbose(ex.ToString());
                        }

                        if (matches != null && matches.Length > 0)
                        {
                            // add extension.
                            for (int i = 0; i < pathExtSegments.Length; i++)
                            {
                                string fullPath = Path.Combine(pathSegment, $"{command}{pathExtSegments[i]}");
                                if (matches.Any(p => p.Equals(fullPath, StringComparison.OrdinalIgnoreCase)))
                                {
                                    trace?.Info($"Location: '{fullPath}'");
                                    return(fullPath);
                                }
                            }
                        }
                    }
#else
                    try
                    {
                        matches = Directory.GetFiles(pathSegment, command);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        trace?.Info("Ignore UnauthorizedAccess exception during Which.");
                        trace?.Verbose(ex.ToString());
                    }

                    if (matches != null && matches.Length > 0)
                    {
                        trace?.Info("Location: '{matches.First()}'");
                        return(matches.First());
                    }
#endif
                }
            }

            trace?.Info("Not found.");
            if (require)
            {
                throw new FileNotFoundException(
                          message: StringUtil.Loc("FileNotFound", command),
                          fileName: command);
            }

            return(null);
        }
コード例 #3
0
        public string Which(string command)
        {
            ArgUtil.NotNullOrEmpty(command, nameof(command));

            Trace.Verbose($"{nameof(command)}={command}");

#if OS_WINDOWS
            string path = Environment.GetEnvironmentVariable("Path");
#else
            string path = Environment.GetEnvironmentVariable("PATH");
#endif
            if (string.IsNullOrEmpty(path))
            {
                return(null);
            }

#if OS_WINDOWS
            char pathSep = ';';
#else
            char pathSep = ':';
#endif

            string[] pathSegments = path.Split(new Char[] { pathSep }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < pathSegments.Length; i++)
            {
                pathSegments[i] = Environment.ExpandEnvironmentVariables(pathSegments[i]);
            }

            foreach (string pathSegment in pathSegments)
            {
                if (!string.IsNullOrEmpty(pathSegment) && Directory.Exists(pathSegment))
                {
                    string[] matches;
#if OS_WINDOWS
                    string pathExt = Environment.GetEnvironmentVariable("PATHEXT");
                    if (string.IsNullOrEmpty(pathExt))
                    {
                        // XP's system default value for PATHEXT system variable
                        pathExt = ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh";
                    }

                    string[] pathExtSegments = pathExt.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);

                    // if command already has an extension.
                    if (pathExtSegments.Any(ext => command.EndsWith(ext, StringComparison.OrdinalIgnoreCase)))
                    {
                        matches = Directory.GetFiles(pathSegment, command);
                        if (matches != null && matches.Length > 0)
                        {
                            return(matches.First());
                        }
                    }
                    else
                    {
                        string searchPattern;
                        searchPattern = StringUtil.Format($"{command}.*");
                        matches       = Directory.GetFiles(pathSegment, searchPattern);
                        if (matches != null && matches.Length > 0)
                        {
                            // add extension.
                            for (int i = 0; i < pathExtSegments.Length; i++)
                            {
                                string fullPath = Path.Combine(pathSegment, StringUtil.Format($"{command}{pathExtSegments[i]}"));
                                if (matches.Any(p => p.Equals(fullPath, StringComparison.OrdinalIgnoreCase)))
                                {
                                    return(fullPath);
                                }
                            }
                        }
                    }
#else
                    matches = Directory.GetFiles(pathSegment, command);
                    if (matches != null && matches.Length > 0)
                    {
                        return(matches.First());
                    }
#endif
                }
            }

            return(null);
        }
コード例 #4
0
        public async Task <int> ExecuteAsync(
            string workingDirectory,
            string fileName,
            string arguments,
            IDictionary <string, string> environment,
            bool requireExitCodeZero,
            Encoding outputEncoding,
            bool killProcessOnCancel,
            InputQueue <string> redirectStandardIn,
            bool inheritConsoleHandler,
            CancellationToken cancellationToken)
        {
            ArgUtil.Null(_proc, nameof(_proc));
            ArgUtil.NotNullOrEmpty(fileName, nameof(fileName));

            Trace.Info("Starting process:");
            Trace.Info($"  File name: '{fileName}'");
            Trace.Info($"  Arguments: '{arguments}'");
            Trace.Info($"  Working directory: '{workingDirectory}'");
            Trace.Info($"  Require exit code zero: '{requireExitCodeZero}'");
            Trace.Info($"  Encoding web name: {outputEncoding?.WebName} ; code page: '{outputEncoding?.CodePage}'");
            Trace.Info($"  Force kill process on cancellation: '{killProcessOnCancel}'");
            Trace.Info($"  Redirected STDIN: '{redirectStandardIn != null}'");
            Trace.Info($"  Persist current code page: '{inheritConsoleHandler}'");

            _proc = new Process();
            _proc.StartInfo.FileName               = fileName;
            _proc.StartInfo.Arguments              = arguments;
            _proc.StartInfo.WorkingDirectory       = workingDirectory;
            _proc.StartInfo.UseShellExecute        = false;
            _proc.StartInfo.CreateNoWindow         = !inheritConsoleHandler;
            _proc.StartInfo.RedirectStandardInput  = true;
            _proc.StartInfo.RedirectStandardError  = true;
            _proc.StartInfo.RedirectStandardOutput = true;

            // Ensure we process STDERR even the process exit event happen before we start read STDERR stream.
            if (_proc.StartInfo.RedirectStandardError)
            {
                Interlocked.Increment(ref _asyncStreamReaderCount);
            }

            // Ensure we process STDOUT even the process exit event happen before we start read STDOUT stream.
            if (_proc.StartInfo.RedirectStandardOutput)
            {
                Interlocked.Increment(ref _asyncStreamReaderCount);
            }

#if OS_WINDOWS
            // If StandardErrorEncoding or StandardOutputEncoding is not specified the on the
            // ProcessStartInfo object, then .NET PInvokes to resolve the default console output
            // code page:
            //      [DllImport("api-ms-win-core-console-l1-1-0.dll", SetLastError = true)]
            //      public extern static uint GetConsoleOutputCP();
            StringUtil.EnsureRegisterEncodings();
#endif
            if (outputEncoding != null)
            {
                _proc.StartInfo.StandardErrorEncoding  = outputEncoding;
                _proc.StartInfo.StandardOutputEncoding = outputEncoding;
            }

            // Copy the environment variables.
            if (environment != null && environment.Count > 0)
            {
                foreach (KeyValuePair <string, string> kvp in environment)
                {
                    _proc.StartInfo.Environment[kvp.Key] = kvp.Value;
                }
            }

            // Set the TF_BUILD env variable.
            _proc.StartInfo.Environment["TF_BUILD"] = "True";

            // Hook up the events.
            _proc.EnableRaisingEvents = true;
            _proc.Exited += ProcessExitedHandler;

            // Start the process.
            _stopWatch = Stopwatch.StartNew();
            _proc.Start();

            // Start the standard error notifications, if appropriate.
            if (_proc.StartInfo.RedirectStandardError)
            {
                StartReadStream(_proc.StandardError, _errorData);
            }

            // Start the standard output notifications, if appropriate.
            if (_proc.StartInfo.RedirectStandardOutput)
            {
                StartReadStream(_proc.StandardOutput, _outputData);
            }

            if (_proc.StartInfo.RedirectStandardInput)
            {
                if (redirectStandardIn != null)
                {
                    StartWriteStream(redirectStandardIn, _proc.StandardInput);
                }
                else
                {
                    // Close the input stream. This is done to prevent commands from blocking the build waiting for input from the user.
                    _proc.StandardInput.Close();
                }
            }

            using (var registration = cancellationToken.Register(async() => await CancelAndKillProcessTree(killProcessOnCancel)))
            {
                Trace.Info($"Process started with process id {_proc.Id}, waiting for process exit.");
                while (true)
                {
                    Task outputSignal = _outputProcessEvent.WaitAsync();
                    var  signaled     = await Task.WhenAny(outputSignal, _processExitedCompletionSource.Task);

                    if (signaled == outputSignal)
                    {
                        ProcessOutput();
                    }
                    else
                    {
                        _stopWatch.Stop();
                        break;
                    }
                }

                // Just in case there was some pending output when the process shut down go ahead and check the
                // data buffers one last time before returning
                ProcessOutput();

                Trace.Info($"Finished process {_proc.Id} with exit code {_proc.ExitCode}, and elapsed time {_stopWatch.Elapsed}.");
            }

            cancellationToken.ThrowIfCancellationRequested();

            // Wait for process to finish.
            if (_proc.ExitCode != 0 && requireExitCodeZero)
            {
                throw new ProcessExitCodeException(exitCode: _proc.ExitCode, fileName: fileName, arguments: arguments);
            }

            return(_proc.ExitCode);
        }
コード例 #5
0
ファイル: IOUtil.cs プロジェクト: danbridgellc/vsts-agent
        public static void DeleteDirectory(string path, CancellationToken cancellationToken)
        {
            ArgUtil.NotNullOrEmpty(path, nameof(path));
            DirectoryInfo directory = new DirectoryInfo(path);

            if (!directory.Exists)
            {
                return;
            }

            // Initialize a concurrent stack to store the directories. The directories
            // cannot be deleted until the files are deleted.
            var directories = new ConcurrentStack <DirectoryInfo>();

            // Remove the readonly flag and store the root directory.
            RemoveReadOnly(directory);
            directories.Push(directory);

            // Create a new token source for the parallel query. The parallel query should be
            // canceled after the first error is encountered. Otherwise the number of exceptions
            // could get out of control for a large directory with access denied on every file.
            using (var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
            {
                // Delete all files and store all subdirectories.
                directory
                .EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
                .AsParallel()
                .WithCancellation(tokenSource.Token)
                .ForAll((FileSystemInfo item) =>
                {
                    bool success = false;
                    try
                    {
                        // Check if the item is a file.
                        var file = item as FileInfo;
                        if (file != null)
                        {
                            // Delete the file.
                            RemoveReadOnly(file);
                            file.Delete();
                            success = true;
                            return;
                        }

                        // The item is a directory.
                        var subdirectory = item as DirectoryInfo;
                        ArgUtil.NotNull(subdirectory, nameof(subdirectory));

                        // Remove the readonly attribute and store the subdirectory.
                        RemoveReadOnly(subdirectory);
                        directories.Push(subdirectory);
                        success = true;
                    }
                    finally
                    {
                        if (!success)
                        {
                            tokenSource.Cancel();     // Cancel is thread-safe.
                        }
                    }
                });
            }

            // Delete the directories.
            foreach (DirectoryInfo dir in directories.OrderByDescending(x => x.FullName.Length))
            {
                cancellationToken.ThrowIfCancellationRequested();
                dir.Delete();
            }
        }