diff --git a/src/DirOption.cs b/src/DirOption.cs index a71933f..8c4a241 100644 --- a/src/DirOption.cs +++ b/src/DirOption.cs @@ -2,9 +2,17 @@ namespace Dot; public class DirOption : OptionBase { - [Option('f', "filter", HelpText = nameof(Str.FileSearchPattern), Default = "*.*", ResourceType = typeof(Str))] + [Option('e', "exclude", HelpText = nameof(Str.ExcludePathRegexes), ResourceType = typeof(Str))] + public IEnumerable ExcludeRegexes { get; set; } + + [Option('f', "filter", HelpText = nameof(Str.FileSearchPattern), Default = "*", ResourceType = typeof(Str))] public string Filter { get; set; } + + [Option('d', "max-depth", HelpText = nameof(Str.MaxRecursionDepth), Default = int.MaxValue + , ResourceType = typeof(Str))] + public int MaxRecursionDepth { get; set; } + [Value(0, HelpText = nameof(Str.FolderPath), Default = ".", ResourceType = typeof(Str))] public string Path { get; set; } diff --git a/src/FilesTool.cs b/src/FilesTool.cs index 2e10e1d..e36bcb1 100644 --- a/src/FilesTool.cs +++ b/src/FilesTool.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using System.Text.RegularExpressions; using Panel = Spectre.Console.Panel; namespace Dot; @@ -7,6 +8,7 @@ public abstract class FilesTool : ToolBase where TOption : Dir { private int _breakCnt; //跳过文件数 private ProgressTask _childTask; //子任务进度 + private int _excludeCnt; //排除文件数 private static readonly object _lock = new(); //线程锁 private int _readCnt; //读取文件数 private int _totalCnt; //总文件数 @@ -19,33 +21,31 @@ public abstract class FilesTool : ToolBase where TOption : Dir throw new ArgumentException(nameof(Opt.Path), string.Format(Str.PathNotFound, Opt.Path)); } - private static string[] EnumerateFiles(string path, string searchPattern) + private string[] EnumerateFiles(string path, string searchPattern, out int excludeCnt) { - var fileList = Directory - .EnumerateFiles(path, searchPattern - , new EnumerationOptions { - RecurseSubdirectories = true - , AttributesToSkip = FileAttributes.ReparsePoint - }) - .Where(x => !new[] { ".git", "node_modules" }.Any( - y => x.Contains(y, StringComparison.OrdinalIgnoreCase))) - .ToArray(); + var exCnt = 0; + if (!Opt.ExcludeRegexes.Any()) //默认排除.git 、 node_modules 目录 + Opt.ExcludeRegexes = new[] { @"\.git", "node_modules" }; + var excludeRegexes = Opt.ExcludeRegexes.Select(x => new Regex(x)); + var fileList = Directory.EnumerateFiles(path, searchPattern + , new EnumerationOptions { + RecurseSubdirectories = true + , AttributesToSkip + = FileAttributes.ReparsePoint + , IgnoreInaccessible = true + , MaxRecursionDepth = Opt.MaxRecursionDepth + }) + .Where(x => { + if (!excludeRegexes.Any(y => y.IsMatch(x))) return true; + ++exCnt; + return false; + }) + .ToArray(); + excludeCnt = exCnt; return fileList; } - protected static void CopyFile(string source, string dest) - { - try { - File.Copy(source, dest, true); - } - catch (UnauthorizedAccessException) { - File.SetAttributes(dest, new FileInfo(dest).Attributes & ~FileAttributes.ReadOnly); - File.Copy(source, dest, true); - } - } - - protected FileStream CreateTempFile(out string file) { file = Path.Combine(Path.GetTempPath(), $"{System.Guid.NewGuid()}.tmp"); @@ -85,10 +85,11 @@ public abstract class FilesTool : ToolBase where TOption : Dir _breakCnt += breakCnt; if (readCnt > 0) _childTask.Increment(1); _childTask.Description - = $"{Str.Read}: [green]{_readCnt}[/]/{_totalCnt}, {Str.Write}: [red]{_writeCnt}[/], {Str.Break}: [gray]{_breakCnt}[/]"; + = $"{Str.Read}: [green]{_readCnt}[/]/{_totalCnt}, {Str.Write}: [red]{_writeCnt}[/], {Str.Break}: [gray]{_breakCnt}[/], {Str.Exclude}: [yellow]{_excludeCnt}[/]"; } } + protected void UpdateStats(string key) { _writeStats.AddOrUpdate(key, 1, (_, oldValue) => oldValue + 1); @@ -108,7 +109,7 @@ public abstract class FilesTool : ToolBase where TOption : Dir .StartAsync(async ctx => { var taskSearchfile = ctx.AddTask(Str.SearchingFile).IsIndeterminate(); _childTask = ctx.AddTask("-/-", false); - fileList = EnumerateFiles(Opt.Path, Opt.Filter); + fileList = EnumerateFiles(Opt.Path, Opt.Filter, out _excludeCnt); _totalCnt = fileList.Count(); taskSearchfile.IsIndeterminate(false); taskSearchfile.Increment(100); diff --git a/src/Lang/Str.en-US.resx b/src/Lang/Str.en-US.resx index 69b4561..646d811 100644 --- a/src/Lang/Str.en-US.resx +++ b/src/Lang/Str.en-US.resx @@ -1,191 +1,190 @@ - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - + + The input text is empty - + Find files... - + The specified path "{0}" does not exist - + {0} files - + Read: {0}/{1}, processed: {2}, skipped: {3} - + {0}(copied to clipboard) - + File wildcards - + Directory path to be processed - + Convert newline characters to LF - + GUID tool - + Use uppercase output - + Random password generator - + Password length - + BitSet 1:[0-9],2:[a-z],4:[A-Z],8:[ascii.0x21-0x2F] - + Remove line breaks and spaces at the end of the file - + Remove the uf8 bom of the file - + Text to be processed (clipboard value is taken by default) - + Press any key to continue... - + No documents to be processed - + Timeout for connecting to the NTP server (milliseconds) - + Synchronize local time - + Success {0}/{1}, the average value of the clock offset of the machine:{2}ms - + {0}/{1} NTP servers - + {0} In communication... - + {0}, local clock offset: {1} ms - + Local time has been synchronized - + Server - + Status - + Local clock offset - + Time synchronization tool - + Text encoding tool - + Screen coordinate color selection tool - + Click the left mouse button to copy the colors and coordinates to the clipboard - + Public network ip: - + Synchronize local time - + IP tools - + Keep the session after executing the command - + NTP server standard clock: {0} - + Git batch operation tool - + Parameters passed to Git - + OK - + Find all git repository directories under "{0}"... - + Git output encoding - + Directory search depth - + Clipboard does not contain correct Json string - + JsonTools - + Compress Json text - + Format JSON text - + generate entity classes - + Json text escaped into a string - + Enable write mode - + Read-only mode, the file will not be modified in real time! - + read - + write - + skip - + Write statistics \ No newline at end of file diff --git a/src/Lang/Str.resx b/src/Lang/Str.resx index 4fc22a6..52c2497 100644 --- a/src/Lang/Str.resx +++ b/src/Lang/Str.resx @@ -143,6 +143,12 @@ 没有需要处理的文件 + + 排除路径的正则表达式 + + + 排除 + 成功 {0}/{1} , 本机时钟偏移平均值: {2} ms diff --git a/src/RmBom/Main.cs b/src/RmBom/Main.cs index d650f7f..b6cc3e3 100644 --- a/src/RmBom/Main.cs +++ b/src/RmBom/Main.cs @@ -33,7 +33,7 @@ public sealed class Main : FilesTool