Skip to content

Commit 8e2a1c7

Browse files
committed
Optimised exclusion matching. Added *IgnorePathsEndingWith settings. Require slashes in the start of *IgnorePathsStartingWith entries.
1 parent 14065fe commit 8e2a1c7

File tree

6 files changed

+62
-19
lines changed

6 files changed

+62
-19
lines changed

AsyncToSyncCodeRoundtripSynchroniserMonitorNet.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@
9999
<Reference Include="Nito.Disposables, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
100100
<HintPath>packages\Nito.Disposables.2.0.0\lib\netstandard1.0\Nito.Disposables.dll</HintPath>
101101
</Reference>
102+
<Reference Include="NReco.Text.AhoCorasickDoubleArrayTrie, Version=1.0.2.0, Culture=neutral, PublicKeyToken=70ca172a68680917, processorArchitecture=MSIL">
103+
<HintPath>..\..\FolderSync\FolderSyncNet\packages\NReco.Text.AhoCorasickDoubleArrayTrie.1.0.2\lib\net40\NReco.Text.AhoCorasickDoubleArrayTrie.dll</HintPath>
104+
</Reference>
102105
<Reference Include="System" />
103106
<Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
104107
<HintPath>packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>

Extensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ public static string GetLongPath(string path)
8181

8282
//@"\\?\" prefix is needed for reading from long paths: https://stackoverflow.com/questions/44888844/directorynotfoundexception-when-using-long-paths-in-net-4-7 and https://superuser.com/questions/1617012/support-of-the-unc-server-share-syntax-in-windows
8383

84-
if (path.Substring(0, 2) == @"\\") //network path or path already starting with \\?\
84+
if (
85+
path.Length >= 2 //necessary to avoid exceptions in Substring()
86+
&& path.Substring(0, 2) == @"\\" //network path or path already starting with \\?\
87+
)
8588
{
8689
return path;
8790
}

Program.cs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using myoddweb.directorywatcher.interfaces;
2626
using Nito.AspNetBackgroundTasks;
2727
using Nito.AsyncEx;
28+
using NReco.Text;
2829

2930
namespace AsyncToSyncCodeRoundtripSynchroniserMonitor
3031
{
@@ -42,12 +43,17 @@ internal static class Global
4243
public static long MaxFileSizeMB = 2048;
4344

4445

45-
public static List<string> WatchedCodeExtension = new List<string>() { "cs", "py" };
46-
public static List<string> WatchedResXExtension = new List<string>() { "resx" };
46+
public static HashSet<string> WatchedCodeExtension = new HashSet<string>() { "cs", "py" };
47+
public static HashSet<string> WatchedResXExtension = new HashSet<string>() { "resx" };
4748

48-
public static List<string> ExcludedExtensions = new List<string>() { "*~", "tmp" };
49-
public static List<string> IgnorePathsStartingWith = new List<string>();
50-
public static List<string> IgnorePathsContaining = new List<string>();
49+
public static HashSet<string> ExcludedExtensions = new HashSet<string>() { "*~", "tmp" };
50+
51+
public static List<string> IgnorePathsStartingWithList = new List<string>();
52+
public static List<string> IgnorePathsContainingList = new List<string>();
53+
public static List<string> IgnorePathsEndingWithList = new List<string>();
54+
55+
public static bool IgnorePathsContainingACHasAny = false;
56+
public static AhoCorasickDoubleArrayTrie<bool> IgnorePathsContainingAC = new AhoCorasickDoubleArrayTrie<bool>();
5157

5258
public static string AsyncPath = "";
5359
public static string SyncPath = "";
@@ -97,6 +103,15 @@ public bool Is(EventAction action)
97103

98104
internal class Program
99105
{
106+
//let null char mark start and end of a filename
107+
//https://stackoverflow.com/questions/54205087/how-can-i-create-a-file-with-null-bytes-in-the-filename
108+
//https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names
109+
//https://serverfault.com/questions/242110/which-common-characters-are-illegal-in-unix-and-windows-filesystems
110+
public static readonly string NullChar = new string(new char[] { (char)0 });
111+
112+
public static readonly string DirectorySeparatorChar = new string(new char[] { Path.DirectorySeparatorChar });
113+
114+
100115
private static byte[] GetHash(string inputString)
101116
{
102117
#pragma warning disable SCS0006 //Warning SCS0006 Weak hashing function
@@ -151,14 +166,26 @@ private static void Main()
151166
Global.AsyncPathMinFreeSpace = fileConfig.GetLong("AsyncPathMinFreeSpace") ?? 0;
152167
Global.SyncPathMinFreeSpace = fileConfig.GetLong("SyncPathMinFreeSpace") ?? 0;
153168

154-
Global.WatchedCodeExtension = fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "WatchedCodeExtensions", "WatchedCodeExtension");
155-
Global.WatchedResXExtension = fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "WatchedResXExtensions", "WatchedResXExtension");
169+
Global.WatchedCodeExtension = new HashSet<string>(fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "WatchedCodeExtensions", "WatchedCodeExtension"));
170+
Global.WatchedResXExtension = new HashSet<string>(fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "WatchedResXExtensions", "WatchedResXExtension"));
156171

157172
//this would need Microsoft.Extensions.Configuration and Microsoft.Extensions.Configuration.Binder packages
158-
Global.ExcludedExtensions = fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "ExcludedExtensions", "ExcludedExtension"); //NB! UpperOnWindows
173+
Global.ExcludedExtensions = new HashSet<string>(fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "ExcludedExtensions", "ExcludedExtension")); //NB! UpperOnWindows
159174

160-
Global.IgnorePathsStartingWith = fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "IgnorePathsStartingWith", "IgnorePathStartingWith"); //NB! UpperOnWindows
161-
Global.IgnorePathsContaining = fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "IgnorePathsContaining", "IgnorePathContaining"); //NB! UpperOnWindows
175+
Global.IgnorePathsStartingWithList = fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "IgnorePathsStartingWith", "IgnorePathStartingWith"); //NB! UpperOnWindows
176+
Global.IgnorePathsContainingList = fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "IgnorePathsContaining", "IgnorePathContaining"); //NB! UpperOnWindows
177+
Global.IgnorePathsEndingWithList = fileConfig.GetListUpperOnWindows(Global.CaseSensitiveFilenames, "IgnorePathsEndingWith", "IgnorePathEndingWith"); //NB! UpperOnWindows
178+
179+
var ACInput = Global.IgnorePathsStartingWithList.Select(x => new KeyValuePair<string, bool>(NullChar + x, false))
180+
.Concat(Global.IgnorePathsContainingList.Select(x => new KeyValuePair<string, bool>(x, false)))
181+
.Concat(Global.IgnorePathsEndingWithList.Select(x => new KeyValuePair<string, bool>(x + NullChar, false)))
182+
.ToList();
183+
184+
if (ACInput.Any()) //needed to avoid exceptions
185+
{
186+
Global.IgnorePathsContainingACHasAny = true;
187+
Global.IgnorePathsContainingAC.Build(ACInput);
188+
}
162189

163190

164191
var pathHashes = "";
@@ -377,10 +404,13 @@ private static IAsyncEnumerable<FileInfo> ProcessSubDirs(DirectoryInfo srcDirInf
377404
continue;
378405

379406

380-
var nonFullNameInvariant = ConsoleWatch.GetNonFullName(dirInfo.FullName) + Path.PathSeparator;
407+
var nonFullNameInvariantWithLeadingSlash = DirectorySeparatorChar + Extensions.GetDirPathWithTrailingSlash(ConsoleWatch.GetNonFullName(dirInfo.FullName.ToUpperInvariantOnWindows(Global.CaseSensitiveFilenames)));
381408
if (
382-
Global.IgnorePathsStartingWith.Any(x => nonFullNameInvariant.StartsWith(x))
383-
|| Global.IgnorePathsContaining.Any(x => nonFullNameInvariant.Contains(x))
409+
//Global.IgnorePathsStartingWith.Any(x => nonFullNameInvariantWithLeadingSlash.StartsWith(x))
410+
//|| Global.IgnorePathsContaining.Any(x => nonFullNameInvariantWithLeadingSlash.Contains(x))
411+
//|| Global.IgnorePathsEndingWith.Any(x => nonFullNameInvariantWithLeadingSlash.EndsWith(x))
412+
Global.IgnorePathsContainingACHasAny //needed to avoid exceptions
413+
&& Global.IgnorePathsContainingAC.ParseText(NullChar + nonFullNameInvariantWithLeadingSlash/* + NullChar*/).Any() //NB! no NullChar appended to end since it is dir path not complete file path
384414
)
385415
{
386416
continue;
@@ -1037,7 +1067,7 @@ private static bool IsWatchedFile(string fullName)
10371067
|| Global.WatchedResXExtension.Contains("*")
10381068
)
10391069
&&
1040-
Global.ExcludedExtensions.All(x =>
1070+
Global.ExcludedExtensions.All(x => //TODO: optimise
10411071

10421072
!fullNameInvariant.EndsWith("." + x)
10431073
&&
@@ -1049,11 +1079,14 @@ private static bool IsWatchedFile(string fullName)
10491079
)
10501080
)
10511081
{
1052-
var nonFullNameInvariant = GetNonFullName(fullNameInvariant);
1082+
var nonFullNameInvariantWithLeadingSlash = Program.DirectorySeparatorChar + GetNonFullName(fullNameInvariant);
10531083

10541084
if (
1055-
Global.IgnorePathsStartingWith.Any(x => nonFullNameInvariant.StartsWith(x))
1056-
|| Global.IgnorePathsContaining.Any(x => nonFullNameInvariant.Contains(x))
1085+
//Global.IgnorePathsStartingWith.Any(x => nonFullNameInvariantWithLeadingSlash.StartsWith(x))
1086+
//|| Global.IgnorePathsContaining.Any(x => nonFullNameInvariantWithLeadingSlash.Contains(x))
1087+
//|| Global.IgnorePathsEndingWith.Any(x => nonFullNameInvariantWithLeadingSlash.EndsWith(x))
1088+
Global.IgnorePathsContainingACHasAny //needed to avoid exceptions
1089+
&& Global.IgnorePathsContainingAC.ParseText(Program.NullChar + nonFullNameInvariantWithLeadingSlash + Program.NullChar).Any()
10571090
)
10581091
{
10591092
return false;

appsettings.example.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
"IgnorePathsContaining": [
4949
".localhistory\\",
5050
".vshistory\\"
51+
],
52+
53+
"IgnorePathsEndingWith": [
5154
]
5255
}
5356
}

copyrights.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ MyOddWeb.DirectoryWatcher 0.1.8, 2018 Florent Guelfucci, MIT Licence. https://ww
55
.NET runtime source, .NET Foundation and Contributors, MIT License. https://github.com/dotnet/runtime/blob/5ddc873d9ea6cd4bc6a935fec3057fe89a6932aa/src/libraries/System.IO.FileSystem/src/System/IO/File.cs
66
Nito.AspNetBackgroundTasks 1.0.0, Stephen Cleary, MIT License. https://www.nuget.org/packages/Nito.AspNetBackgroundTasks/
77
Nito.AsyncEx 5.0.0, Stephen Cleary, MIT License. https://www.nuget.org/packages/Nito.AsyncEx.Coordination/
8-
8+
NReco.Text.AhoCorasickDoubleArrayTrie 1.0.2, 2017-2019 Vitaliy Fedorchenko, Apache-2.0 License. https://www.nuget.org/packages/NReco.Text.AhoCorasickDoubleArrayTrie

packages.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<package id="Nito.AsyncEx.Tasks" version="5.0.0" targetFramework="net46" />
2020
<package id="Nito.Collections.Deque" version="1.0.4" targetFramework="net46" />
2121
<package id="Nito.Disposables" version="2.0.0" targetFramework="net46" />
22+
<package id="NReco.Text.AhoCorasickDoubleArrayTrie" version="1.0.2" targetFramework="net46" />
2223
<package id="System.AppContext" version="4.3.0" targetFramework="net46" />
2324
<package id="System.Collections" version="4.3.0" targetFramework="net46" />
2425
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net46" />

0 commit comments

Comments
 (0)