Skip to content

Commit a058048

Browse files
committed
Make configuration reader backwards-compatible. Perform case-insensitive filename matching only under Windows. Minor performance optimisation.
1 parent 7c514fd commit a058048

File tree

4 files changed

+118
-25
lines changed

4 files changed

+118
-25
lines changed

AsyncToSyncCodeRoundtripSynchroniserMonitorNet.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
<ItemGroup>
156156
<Compile Include="AsyncToSyncConverter.cs" />
157157
<Compile Include="BinaryFileExtensions.cs" />
158+
<Compile Include="ConfigParser.cs" />
158159
<Compile Include="Extensions.cs" />
159160
<Compile Include="FileExtensions.cs" />
160161
<Compile Include="Program.cs" />
@@ -165,7 +166,9 @@
165166
<ItemGroup>
166167
<None Include="App.config" />
167168
<None Include="app.manifest" />
168-
<None Include="appsettings.example.json" />
169+
<None Include="appsettings.example.json">
170+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
171+
</None>
169172
<None Include="appsettings.json">
170173
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
171174
</None>

ConfigParser.cs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//
2+
// Licensed to Roland Pihlakas under one or more agreements.
3+
// Roland Pihlakas licenses this file to you under the GNU Lesser General Public License, ver 2.1.
4+
// See the LICENSE and copyrights.txt files for more information.
5+
//
6+
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Runtime.InteropServices;
10+
using Microsoft.Extensions.Configuration;
11+
12+
namespace AsyncToSyncCodeRoundtripSynchroniserMonitor
13+
{
14+
internal static class ConfigParser
15+
{
16+
public static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
17+
public static readonly bool IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
18+
public static readonly bool IsMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
19+
20+
public static string ToUpperInvariantOnWindows(this string text)
21+
{
22+
if (IsWindows) //assume NTFS or FAT filesystem which are usually case-insensitive
23+
return text?.ToUpperInvariant();
24+
else
25+
return text;
26+
}
27+
28+
public static string GetTextUpperOnWindows(this IConfiguration config, params string[] sectionKeyAlternateNames)
29+
{
30+
if (IsWindows) //assume NTFS or FAT filesystem which are usually case-insensitive
31+
return config.GetTextUpper(sectionKeyAlternateNames);
32+
else
33+
return config.GetText(sectionKeyAlternateNames);
34+
}
35+
36+
public static string GetTextUpper(this IConfiguration config, params string[] sectionKeyAlternateNames)
37+
{
38+
return config.GetText(sectionKeyAlternateNames)?.ToUpperInvariant();
39+
}
40+
41+
public static string GetText(this IConfiguration config, params string[] sectionKeyAlternateNames)
42+
{
43+
foreach (var sectionKeyAlternateName in sectionKeyAlternateNames)
44+
{
45+
var text = config[sectionKeyAlternateName];
46+
if (text != null)
47+
return text;
48+
}
49+
50+
return null;
51+
}
52+
53+
public static List<string> GetListUpperOnWindows(this IConfiguration config, params string[] sectionKeyAlternateNames)
54+
{
55+
if (IsWindows) //assume NTFS or FAT filesystem which are usually case-insensitive
56+
return config.GetListUpper(sectionKeyAlternateNames);
57+
else
58+
return config.GetList(sectionKeyAlternateNames);
59+
}
60+
61+
public static List<string> GetListUpper(this IConfiguration config, params string[] sectionKeyAlternateNames)
62+
{
63+
return config.GetList(sectionKeyAlternateNames)
64+
.Select(x => x.ToUpperInvariant())
65+
.ToList();
66+
}
67+
68+
public static List<string> GetList(this IConfiguration config, params string[] sectionKeyAlternateNames)
69+
{
70+
foreach (var sectionKeyAlternateName in sectionKeyAlternateNames)
71+
{
72+
var list = config.GetSection(sectionKeyAlternateName).GetList();
73+
if (list.Count > 0)
74+
return list;
75+
}
76+
77+
return new List<string>();
78+
}
79+
80+
public static List<string> GetList(this IConfigurationSection config)
81+
{
82+
if (config.Value != null)
83+
return new List<string>() { config.Value };
84+
else
85+
return config.GetChildren().Select(c => c.Value).ToList();
86+
}
87+
}
88+
}

Program.cs

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -109,25 +109,24 @@ private static void Main()
109109

110110
var fileConfig = config.GetSection("Files");
111111

112-
Global.Bidirectional = fileConfig["Bidirectional"]?.ToUpperInvariant() != "FALSE"; //default is true
112+
Global.Bidirectional = fileConfig.GetTextUpper("Bidirectional") != "FALSE"; //default is true
113113

114-
Global.AsyncPath = fileConfig["AsyncPath"];
115-
Global.SyncPath = fileConfig["SyncPath"];
114+
Global.AsyncPath = fileConfig.GetTextUpperOnWindows("AsyncPath");
115+
Global.SyncPath = fileConfig.GetTextUpperOnWindows("SyncPath");
116116

117-
Global.WatchedCodeExtension = fileConfig.GetSection("WatchedCodeExtension").GetChildren().Select(c => c.Value.ToUpperInvariant()).ToList();
118-
Global.WatchedResXExtension = fileConfig.GetSection("WatchedResXExtension").GetChildren().Select(c => c.Value.ToUpperInvariant()).ToList();
117+
Global.WatchedCodeExtension = fileConfig.GetListUpperOnWindows("WatchedCodeExtensions", "WatchedCodeExtension");
118+
Global.WatchedResXExtension = fileConfig.GetListUpperOnWindows("WatchedResXExtensions", "WatchedResXExtension");
119119

120120
//this would need Microsoft.Extensions.Configuration and Microsoft.Extensions.Configuration.Binder packages
121-
//Global.ExcludedExtensions = fileConfig.GetSection("ExcludedExtensions").Get<string[]>();
122-
Global.ExcludedExtensions = fileConfig.GetSection("ExcludedExtensions").GetChildren().Select(c => c.Value.ToUpperInvariant()).ToList(); //NB! .ToUpperInvariant()
121+
Global.ExcludedExtensions = fileConfig.GetListUpperOnWindows("ExcludedExtensions", "ExcludedExtension"); //NB! UpperOnWindows
123122

124-
Global.IgnorePathsStartingWith = fileConfig.GetSection("IgnorePathsStartingWith").GetChildren().Select(c => c.Value.ToUpperInvariant()).ToList(); //NB! .ToUpperInvariant()
125-
Global.IgnorePathsContaining = fileConfig.GetSection("IgnorePathsContaining").GetChildren().Select(c => c.Value.ToUpperInvariant()).ToList(); //NB! .ToUpperInvariant()
123+
Global.IgnorePathsStartingWith = fileConfig.GetListUpperOnWindows("IgnorePathsStartingWith", "IgnorePathStartingWith"); //NB! UpperOnWindows
124+
Global.IgnorePathsContaining = fileConfig.GetListUpperOnWindows("IgnorePathsContaining", "IgnorePathContaining"); //NB! UpperOnWindows
126125

127126

128127
var pathHashes = "";
129-
pathHashes += "_" + GetHashString(Global.AsyncPath.ToUpperInvariant());
130-
pathHashes += "_" + GetHashString(Global.SyncPath.ToUpperInvariant());
128+
pathHashes += "_" + GetHashString(Global.AsyncPath);
129+
pathHashes += "_" + GetHashString(Global.SyncPath);
131130

132131
//NB! prevent multiple instances from starting on same directories
133132
using (Mutex mutex = new Mutex(false, "Global\\AsyncToSyncCodeRoundtripSynchroniserMonitor_" + pathHashes))
@@ -414,11 +413,13 @@ public static async Task WriteException(Exception ex, Context context)
414413

415414
public static string GetNonFullName(string fullName)
416415
{
417-
if (fullName.ToUpperInvariant().StartsWith(Global.AsyncPath.ToUpperInvariant()))
416+
var fullNameInvariant = fullName.ToUpperInvariantOnWindows();
417+
418+
if (fullNameInvariant.StartsWith(Global.AsyncPath))
418419
{
419420
return fullName.Substring(Global.AsyncPath.Length);
420421
}
421-
else if (fullName.ToUpperInvariant().StartsWith(Global.SyncPath.ToUpperInvariant()))
422+
else if (fullNameInvariant.StartsWith(Global.SyncPath))
422423
{
423424
return fullName.Substring(Global.SyncPath.Length);
424425
}
@@ -430,13 +431,14 @@ public static string GetNonFullName(string fullName)
430431

431432
public static string GetOtherFullName(string fullName)
432433
{
434+
var fullNameInvariant = fullName.ToUpperInvariantOnWindows();
433435
var nonFullName = GetNonFullName(fullName);
434436

435-
if (fullName.ToUpperInvariant().StartsWith(Global.AsyncPath.ToUpperInvariant()))
437+
if (fullNameInvariant.StartsWith(Global.AsyncPath))
436438
{
437439
return Path.Combine(Global.SyncPath, nonFullName);
438440
}
439-
else if (fullName.ToUpperInvariant().StartsWith(Global.SyncPath.ToUpperInvariant()))
441+
else if (fullNameInvariant.StartsWith(Global.SyncPath))
440442
{
441443
return Path.Combine(Global.AsyncPath, nonFullName);
442444
}
@@ -533,18 +535,18 @@ public static async Task FileUpdated(string fullName, Context context)
533535
var otherFullName = GetOtherFullName(fullName);
534536
using (await Global.FileOperationLocks.LockAsync(fullName, otherFullName, context.Token))
535537
{
536-
var fullNameInvariant = fullName.ToUpperInvariant();
538+
var fullNameInvariant = fullName.ToUpperInvariantOnWindows();
537539

538540
if (
539-
Global.WatchedCodeExtension.Any(x => fullNameInvariant.EndsWith("." + x.ToUpperInvariant()))
541+
Global.WatchedCodeExtension.Any(x => fullNameInvariant.EndsWith("." + x))
540542
|| Global.WatchedCodeExtension.Contains("*")
541543
)
542544
{
543-
if (fullName.ToUpperInvariant().StartsWith(Global.AsyncPath.ToUpperInvariant()))
545+
if (fullNameInvariant.StartsWith(Global.AsyncPath))
544546
{
545547
await AsyncToSyncConverter.AsyncFileUpdated(fullName, context);
546548
}
547-
else if (fullName.ToUpperInvariant().StartsWith(Global.SyncPath.ToUpperInvariant())) //NB!
549+
else if (fullNameInvariant.StartsWith(Global.SyncPath)) //NB!
548550
{
549551
await SyncToAsyncConverter.SyncFileUpdated(fullName, context);
550552
}
@@ -600,12 +602,12 @@ private static DateTime GetFileTime(string fullName)
600602

601603
private static bool IsWatchedFile(string fullName)
602604
{
603-
var fullNameInvariant = fullName.ToUpperInvariant();
605+
var fullNameInvariant = fullName.ToUpperInvariantOnWindows();
604606

605607
if (
606608
(
607-
Global.WatchedCodeExtension.Any(x => fullNameInvariant.EndsWith("." + x.ToUpperInvariant()))
608-
|| Global.WatchedResXExtension.Any(x => fullNameInvariant.EndsWith("." + x.ToUpperInvariant()))
609+
Global.WatchedCodeExtension.Any(x => fullNameInvariant.EndsWith("." + x))
610+
|| Global.WatchedResXExtension.Any(x => fullNameInvariant.EndsWith("." + x))
609611
|| Global.WatchedCodeExtension.Contains("*")
610612
|| Global.WatchedResXExtension.Contains("*")
611613
)

appsettings.example.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
"AsyncPath": "C:\\yourpath\\yourproject\\",
99

1010

11-
"WatchedCodeExtension": [ "cs" ],
12-
"WatchedResXExtension": [ "resx" ],
11+
"WatchedCodeExtensions": [ "cs" ],
12+
"WatchedResXExtensions": [ "resx" ],
1313

1414
"ExcludedExtensions": [
1515
"*~",

0 commit comments

Comments
 (0)