From 23b62ac066838e7107e512d6d08b60c621f48e64 Mon Sep 17 00:00:00 2001 From: TechieGuy12 Date: Fri, 28 Jan 2022 13:17:13 -0500 Subject: [PATCH] Code cleanup and fixes --- FileWatcher/Configuration/Actions/Action.cs | 47 ++++- FileWatcher/Configuration/Actions/Actions.cs | 2 +- FileWatcher/Configuration/Commands/Command.cs | 54 ++++-- .../Configuration/Commands/Commands.cs | 2 +- FileWatcher/Configuration/Data/Attributes.cs | 2 +- FileWatcher/Configuration/Data/MatchBase.cs | 60 ++++--- FileWatcher/Configuration/Data/Name.cs | 9 +- .../Configuration/Data/PatternMatcher.cs | 2 +- .../Configuration/Exclusions/Exclusions.cs | 3 + FileWatcher/Configuration/Filters/Filters.cs | 3 + .../Configuration/IConfigurationFile.cs | 4 +- FileWatcher/Configuration/Logging.cs | 4 +- .../Configuration/Notifications/Data.cs | 4 +- .../Configuration/Notifications/Header.cs | 4 +- .../Configuration/Notifications/Headers.cs | 9 +- .../Notifications/Notification.cs | 84 ++++----- .../Notifications/Notifications.cs | 20 +-- .../Configuration/Notifications/Request.cs | 38 ++++- FileWatcher/Configuration/RunnableBase.cs | 25 +-- FileWatcher/Configuration/Triggers.cs | 2 +- FileWatcher/Configuration/Watch.cs | 160 ++++++++++-------- FileWatcher/Configuration/Watches.cs | 7 +- FileWatcher/Configuration/XmlFile.cs | 20 ++- FileWatcher/FileSystem/Directory.cs | 13 +- FileWatcher/FileSystem/File.cs | 30 ++-- FileWatcher/FileWatcher.csproj | 4 +- FileWatcher/Logging/Logger.cs | 56 +++--- FileWatcher/Program.cs | 7 +- 28 files changed, 414 insertions(+), 261 deletions(-) diff --git a/FileWatcher/Configuration/Actions/Action.cs b/FileWatcher/Configuration/Actions/Action.cs index 93f0d2a..5b25d14 100644 --- a/FileWatcher/Configuration/Actions/Action.cs +++ b/FileWatcher/Configuration/Actions/Action.cs @@ -15,12 +15,12 @@ namespace TE.FileWatcher.Configuration.Actions public class Action : RunnableBase { // The placeholders for the destination path - private Dictionary _destinationPlaceholders - = new Dictionary(); + //private Dictionary _destinationPlaceholders + // = new Dictionary(); // The placeholders for the source path - private Dictionary _sourcePlaceholders - = new Dictionary(); + //private Dictionary _sourcePlaceholders + // = new Dictionary(); /// /// The type of action to perform. @@ -64,7 +64,7 @@ public enum ActionType /// Gets or sets the destination of the action. /// [XmlElement("destination")] - public string Destination { get; set; } + public string? Destination { get; set; } /// /// Gets or sets the verify flag. @@ -101,8 +101,13 @@ public override void Run(string watchPath, string fullPath, TriggerType trigger) return; } - string source = GetSource(watchPath, fullPath); - string destination = GetDestination(watchPath, fullPath); + string? source = GetSource(watchPath, fullPath); + string? destination = GetDestination(watchPath, fullPath); + + if (string.IsNullOrWhiteSpace(source)) + { + return; + } try { @@ -111,16 +116,36 @@ public override void Run(string watchPath, string fullPath, TriggerType trigger) case ActionType.Copy: if (TEFS.File.IsValid(source)) { + if (string.IsNullOrWhiteSpace(destination)) + { + Logger.WriteLine($"The file '{source}' could not be copied because the destination file was not specified."); + return; + } + File.Copy(source, destination, Verify); Logger.WriteLine($"Copied {source} to {destination}."); } + else + { + Logger.WriteLine($"The file '{source}' could not be copied because the path was not valid, the file doesn't exists, or it was in use."); + } break; case ActionType.Move: if (TEFS.File.IsValid(source)) { + if (string.IsNullOrWhiteSpace(destination)) + { + Logger.WriteLine($"The file '{source}' could not be moved because the destination file was not specified."); + return; + } + File.Move(source, destination, Verify); Logger.WriteLine($"Moved {source} to {destination}."); } + else + { + Logger.WriteLine($"The file '{source}' could not be moved because the path was not valid, the file doesn't exists, or it was in use."); + } break; case ActionType.Delete: if (TEFS.File.IsValid(source)) @@ -128,6 +153,10 @@ public override void Run(string watchPath, string fullPath, TriggerType trigger) File.Delete(source); Logger.WriteLine($"Deleted {source}."); } + else + { + Logger.WriteLine($"The file '{source}' could not be deleted because the path was not valid, the file doesn't exists, or it was in use."); + } break; } } @@ -152,7 +181,7 @@ public override void Run(string watchPath, string fullPath, TriggerType trigger) /// /// The destination string value. /// - private string GetDestination(string watchPath, string fullPath) + private string? GetDestination(string watchPath, string fullPath) { if (string.IsNullOrWhiteSpace(Destination)) { @@ -175,7 +204,7 @@ private string GetDestination(string watchPath, string fullPath) /// /// The source string value. /// - private string GetSource(string watchPath, string fullPath) + private string? GetSource(string watchPath, string fullPath) { if (string.IsNullOrWhiteSpace(Source)) { diff --git a/FileWatcher/Configuration/Actions/Actions.cs b/FileWatcher/Configuration/Actions/Actions.cs index 39ac883..adf04c2 100644 --- a/FileWatcher/Configuration/Actions/Actions.cs +++ b/FileWatcher/Configuration/Actions/Actions.cs @@ -15,7 +15,7 @@ public class Actions /// Gets or sets the list of actions to perform. /// [XmlElement("action")] - public List ActionList { get; set; } + public List? ActionList { get; set; } /// /// Runs all the actions for the watch. diff --git a/FileWatcher/Configuration/Commands/Command.cs b/FileWatcher/Configuration/Commands/Command.cs index ff6d42b..ff38883 100644 --- a/FileWatcher/Configuration/Commands/Command.cs +++ b/FileWatcher/Configuration/Commands/Command.cs @@ -17,10 +17,10 @@ namespace TE.FileWatcher.Configuration.Commands public class Command : RunnableBase { // The process that will run the command - private Process _process; + private Process? _process; // A queue containing the information to start the command process - private ConcurrentQueue _processInfo; + private ConcurrentQueue? _processInfo; // Flag indicating that a process is running private bool _isProcessRunning = false; @@ -29,13 +29,13 @@ public class Command : RunnableBase /// Gets or sets the arguments associated with the file to execute. /// [XmlElement("arguments")] - public string Arguments { get; set; } + public string? Arguments { get; set; } /// /// Gets or sets the full path to the file to executed. /// [XmlElement("path")] - public string Path { get; set; } + public string? Path { get; set; } /// /// Gets or sets the triggers of the action. @@ -72,8 +72,14 @@ public override void Run(string watchPath, string fullPath, TriggerType trigger) return; } - string commandPath = GetCommand(watchPath, fullPath); - string arguments = GetArguments(watchPath, fullPath); + string? commandPath = GetCommand(watchPath, fullPath); + string? arguments = GetArguments(watchPath, fullPath); + + if (string.IsNullOrWhiteSpace(commandPath)) + { + Logger.WriteLine($"The command was not provided. Command was not run."); + return; + } if (!File.Exists(commandPath)) { @@ -88,9 +94,16 @@ public override void Run(string watchPath, string fullPath, TriggerType trigger) _processInfo = new ConcurrentQueue(); } - ProcessStartInfo startInfo = new ProcessStartInfo(); - startInfo.FileName = commandPath; - startInfo.Arguments = arguments; + ProcessStartInfo startInfo = new() + { + FileName = commandPath + }; + + if (arguments != null) + { + startInfo.Arguments = arguments; + } + _processInfo.Enqueue(startInfo); // Execute the next process in the queue @@ -119,12 +132,14 @@ private void Execute() try { - if (_processInfo.TryDequeue(out ProcessStartInfo startInfo)) + if (_processInfo.TryDequeue(out ProcessStartInfo? startInfo)) { if (File.Exists(startInfo.FileName)) { - _process = new Process(); - _process.StartInfo = startInfo; + _process = new Process + { + StartInfo = startInfo + }; _process.StartInfo.CreateNoWindow = true; _process.StartInfo.UseShellExecute = false; _process.EnableRaisingEvents = true; @@ -142,7 +157,14 @@ private void Execute() } catch (Exception ex) { - Logger.WriteLine($"Could not run the command '{_process.StartInfo.FileName} {_process.StartInfo.Arguments}'. Reason: {ex.Message}"); + if (_process != null) + { + Logger.WriteLine($"Could not run the command '{_process.StartInfo.FileName} {_process.StartInfo.Arguments}'. Reason: {ex.Message}"); + } + else + { + Logger.WriteLine($"Could not run the command. Reason: {ex.Message}"); + } } } @@ -159,7 +181,7 @@ private void Execute() /// /// The command path string value. /// - private string GetArguments(string watchPath, string fullPath) + private string? GetArguments(string watchPath, string fullPath) { if (string.IsNullOrWhiteSpace(Arguments)) { @@ -182,7 +204,7 @@ private string GetArguments(string watchPath, string fullPath) /// /// The command path string value. /// - private string GetCommand(string watchPath, string fullPath) + private string? GetCommand(string watchPath, string fullPath) { if (string.IsNullOrWhiteSpace(Path)) { @@ -201,7 +223,7 @@ private string GetCommand(string watchPath, string fullPath) /// /// The event arguments. /// - private void OnProcessExit(object sender, EventArgs args) + private void OnProcessExit(object? sender, EventArgs args) { _isProcessRunning = false; diff --git a/FileWatcher/Configuration/Commands/Commands.cs b/FileWatcher/Configuration/Commands/Commands.cs index 2ec7283..c154da9 100644 --- a/FileWatcher/Configuration/Commands/Commands.cs +++ b/FileWatcher/Configuration/Commands/Commands.cs @@ -17,7 +17,7 @@ public class Commands /// Gets or sets the list of actions to perform. /// [XmlElement("command")] - public List CommandList { get; set; } + public List? CommandList { get; set; } /// /// Runs all the commands for the watch. diff --git a/FileWatcher/Configuration/Data/Attributes.cs b/FileWatcher/Configuration/Data/Attributes.cs index 808bc61..05bd28c 100644 --- a/FileWatcher/Configuration/Data/Attributes.cs +++ b/FileWatcher/Configuration/Data/Attributes.cs @@ -27,7 +27,7 @@ public HashSet Attribute { get { - HashSet attributes = new HashSet(AttributeStrings.Count); + HashSet attributes = new(AttributeStrings.Count); foreach (string attribute in AttributeStrings) { try diff --git a/FileWatcher/Configuration/Data/MatchBase.cs b/FileWatcher/Configuration/Data/MatchBase.cs index 3691851..91a6cad 100644 --- a/FileWatcher/Configuration/Data/MatchBase.cs +++ b/FileWatcher/Configuration/Data/MatchBase.cs @@ -16,40 +16,40 @@ namespace TE.FileWatcher.Configuration.Data public abstract class MatchBase { // The set of full path to the folders to ignore - private protected HashSet _folders; + private protected HashSet? _folders; // The set of full path to the paths to ignore - private protected HashSet _paths; + private protected HashSet? _paths; // Sets the flag indicating the ignore lists have been populated private protected bool _initialized = false; // The path associated with the watch - private protected string _watchPath; + private protected string? _watchPath; /// /// Gets or sets the files node. /// [XmlElement("files")] - public Files Files { get; set; } + public Files? Files { get; set; } /// /// Gets or sets the folders node. /// [XmlElement("folders")] - public Folders Folders { get; set; } + public Folders? Folders { get; set; } /// /// Gets or sets the paths node. /// [XmlElement("paths")] - public Paths Paths { get; set; } + public Paths? Paths { get; set; } /// /// Gets or sets the attributes node. /// [XmlElement("attributes")] - public Attributes Attributes { get; set; } + public Attributes? Attributes { get; set; } /// /// Gets or sets the type of filter used for logging. @@ -176,10 +176,6 @@ private protected bool FileMatch(string name) Logger.WriteLine($"{FilterTypeName}: The match pattern '{fileName.Pattern}' is a match for file {name}."); break; } - //else - //{ - // Logger.WriteLine($"{FilterTypeName}: The match pattern '{fileName.Pattern}' is not a match for file {name}."); - //} } return isMatch; @@ -216,10 +212,6 @@ private protected bool FolderMatch(string path) Logger.WriteLine($"{FilterTypeName}: The match pattern '{folder.Pattern}' is a match for folder '{path}'."); break; } - //else - //{ - // Logger.WriteLine($"{FilterTypeName}: The match pattern '{folder.Pattern}' is not a match for folder '{path}'."); - //} } return isMatch; @@ -269,6 +261,9 @@ private protected bool PathMatch(string path) /// the folders. This is then used to compare with any folder that /// is changed. /// + /// + /// Thrown when there is a problem with the path. + /// private void GetFolders() { if (Folders == null) @@ -281,16 +276,13 @@ private void GetFolders() return; } - //_folders = new HashSet( - // Folders.Name.Count, - // StringComparer.OrdinalIgnoreCase); - - //foreach (string folder in Folders.Name) foreach (Name folderName in Folders.Name) { - //string folderPath = Path.Combine(_watchPath, folderName.Value); - folderName.Pattern = Path.Combine(_watchPath, folderName.Pattern); - //_folders.Add(folderPath); + if (_watchPath != null && folderName.Pattern != null) + { + folderName.Pattern = + Path.Combine(_watchPath, folderName.Pattern); + } } } @@ -301,6 +293,9 @@ private void GetFolders() /// to create the absolute path of each specified path value. This is /// then used to compare with any path that is changed. /// + /// + /// Thrown when there is a problem with the path. + /// private void GetPaths() { if (Paths == null) @@ -319,15 +314,23 @@ private void GetPaths() foreach (string path in Paths.Path) { - string fullPath = Path.Combine(_watchPath, path); - _paths.Add(fullPath); + if (_watchPath != null) + { + string fullPath = Path.Combine(_watchPath, path); + _paths.Add(fullPath); + } } } /// /// Initialize the values in the exclusion lists. /// - /// + /// + /// The path to watch. + /// + /// + /// Thrown when there is a problem with the path. + /// private protected void Initialize(string watchPath) { _watchPath = watchPath; @@ -355,6 +358,9 @@ private protected void Initialize(string watchPath) /// /// true of a match is found, otherwise false. /// + /// + /// Thrown when there is a problem with the path. + /// private protected bool IsMatchFound(string watchPath, string name, string fullPath) { if (string.IsNullOrWhiteSpace(watchPath) || string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(fullPath)) @@ -398,7 +404,7 @@ private protected bool IsMatchFound(string watchPath, string name, string fullPa /// /// Thrown when there is a problem with the path. /// - private protected bool IsPathValid(string path) + private protected static bool IsPathValid(string? path) { if (string.IsNullOrWhiteSpace(path)) { diff --git a/FileWatcher/Configuration/Data/Name.cs b/FileWatcher/Configuration/Data/Name.cs index c82c44d..2adec69 100644 --- a/FileWatcher/Configuration/Data/Name.cs +++ b/FileWatcher/Configuration/Data/Name.cs @@ -16,13 +16,13 @@ namespace TE.FileWatcher.Configuration.Data public class Name { // The regular expression - private Regex _regex; + private Regex? _regex; /// /// Gets or sets the name pattern to match. /// [XmlText] - public string Pattern { get; set; } + public string? Pattern { get; set; } /// /// Checks to see if the property provides a @@ -37,6 +37,11 @@ public class Name /// public bool IsMatch(string value) { + if (string.IsNullOrWhiteSpace(Pattern)) + { + return false; + } + bool isMatch = value.Equals(Pattern); if (!isMatch) { diff --git a/FileWatcher/Configuration/Data/PatternMatcher.cs b/FileWatcher/Configuration/Data/PatternMatcher.cs index 49a1376..147ca6b 100644 --- a/FileWatcher/Configuration/Data/PatternMatcher.cs +++ b/FileWatcher/Configuration/Data/PatternMatcher.cs @@ -163,7 +163,7 @@ public static bool StrictMatchPattern(string expression, string name) // if name is shorter that the stuff to the right of * in expression, we don't // need to do the string compare, otherwise we compare rightlength characters // and the end of both strings. - if (name.Length >= rightLength && String.Compare(expression, 1, name, name.Length - rightLength, rightLength, StringComparison.OrdinalIgnoreCase) == 0) + if (name.Length >= rightLength && string.Compare(expression, 1, name, name.Length - rightLength, rightLength, StringComparison.OrdinalIgnoreCase) == 0) { return true; } diff --git a/FileWatcher/Configuration/Exclusions/Exclusions.cs b/FileWatcher/Configuration/Exclusions/Exclusions.cs index 9e41886..62531fa 100644 --- a/FileWatcher/Configuration/Exclusions/Exclusions.cs +++ b/FileWatcher/Configuration/Exclusions/Exclusions.cs @@ -30,6 +30,9 @@ public class Exclusions : MatchBase /// /// True if the change is to be ignored, otherwise false. /// + /// + /// Thrown when there is a problem with the path. + /// public bool Exclude(string watchPath, string name, string fullPath) { FilterTypeName = "Exclude"; diff --git a/FileWatcher/Configuration/Filters/Filters.cs b/FileWatcher/Configuration/Filters/Filters.cs index 7ef335f..868711b 100644 --- a/FileWatcher/Configuration/Filters/Filters.cs +++ b/FileWatcher/Configuration/Filters/Filters.cs @@ -29,6 +29,9 @@ public class Filters : MatchBase /// /// True if the change is to be ignored, otherwise false. /// + /// + /// Thrown when there is a problem with the path. + /// public bool IsMatch(string watchPath, string name, string fullPath) { FilterTypeName = "Filter"; diff --git a/FileWatcher/Configuration/IConfigurationFile.cs b/FileWatcher/Configuration/IConfigurationFile.cs index 5b280e9..23942ec 100644 --- a/FileWatcher/Configuration/IConfigurationFile.cs +++ b/FileWatcher/Configuration/IConfigurationFile.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -15,6 +16,7 @@ interface IConfigurationFile /// A object if the file was read successfully, /// otherwise null. /// - public Watches Read(); + [RequiresUnreferencedCode("Could call functionality incompatible with trimming.")] + public Watches? Read(); } } diff --git a/FileWatcher/Configuration/Logging.cs b/FileWatcher/Configuration/Logging.cs index c727174..2c22efc 100644 --- a/FileWatcher/Configuration/Logging.cs +++ b/FileWatcher/Configuration/Logging.cs @@ -16,13 +16,13 @@ namespace TE.FileWatcher.Configuration public class Logging { // The log path - private string _logPath; + private string? _logPath; /// /// Gets or sets the path of the log file. /// [XmlElement("path")] - public string LogPath + public string? LogPath { get { diff --git a/FileWatcher/Configuration/Notifications/Data.cs b/FileWatcher/Configuration/Notifications/Data.cs index 9bb78e3..24fca93 100644 --- a/FileWatcher/Configuration/Notifications/Data.cs +++ b/FileWatcher/Configuration/Notifications/Data.cs @@ -19,13 +19,13 @@ public class Data /// Gets or sets the headers for the request. /// [XmlElement("headers")] - public Headers Headers { get; set; } + public Headers? Headers { get; set; } /// /// Gets or sets the body for the request. /// [XmlElement("body")] - public string Body { get; set; } + public string? Body { get; set; } /// /// Gets or sets the MIME type string value. diff --git a/FileWatcher/Configuration/Notifications/Header.cs b/FileWatcher/Configuration/Notifications/Header.cs index 7a09c5d..9f6edf9 100644 --- a/FileWatcher/Configuration/Notifications/Header.cs +++ b/FileWatcher/Configuration/Notifications/Header.cs @@ -10,9 +10,9 @@ namespace TE.FileWatcher.Configuration.Notifications public class Header { [XmlElement("name")] - public string Name { get; set; } + public string? Name { get; set; } [XmlElement("value")] - public string Value { get; set; } + public string? Value { get; set; } } } diff --git a/FileWatcher/Configuration/Notifications/Headers.cs b/FileWatcher/Configuration/Notifications/Headers.cs index a3af94e..153f417 100644 --- a/FileWatcher/Configuration/Notifications/Headers.cs +++ b/FileWatcher/Configuration/Notifications/Headers.cs @@ -18,7 +18,7 @@ public class Headers /// Get or sets the list of headers to add to a request. /// [XmlElement("header")] - public List
HeaderList { get; set; } + public List
? HeaderList { get; set; } /// /// Sets the headers for a request. @@ -28,14 +28,17 @@ public class Headers /// public void Set(HttpRequestMessage request) { - if (HeaderList.Count <= 0) + if (HeaderList == null || HeaderList.Count <= 0) { return; } foreach (Header header in HeaderList) { - request.Headers.Add(header.Name, header.Value); + if (!string.IsNullOrWhiteSpace(header.Name)) + { + request.Headers.Add(header.Name, header.Value); + } } } } diff --git a/FileWatcher/Configuration/Notifications/Notification.cs b/FileWatcher/Configuration/Notifications/Notification.cs index 8c126e4..926a5ff 100644 --- a/FileWatcher/Configuration/Notifications/Notification.cs +++ b/FileWatcher/Configuration/Notifications/Notification.cs @@ -15,45 +15,19 @@ namespace TE.FileWatcher.Configuration.Notifications public class Notification { // The message to send with the request. - private StringBuilder _message; + private readonly StringBuilder _message; /// /// Gets or sets the URL of the request. /// [XmlElement("url")] - public string Url { get; set; } - - /// - /// Gets the URI value of the string URL. - /// - [XmlIgnore] - public Uri Uri - { - get - { - try - { - if (string.IsNullOrWhiteSpace(Url)) - { - return null; - } - - Uri uri = new Uri(Url); - return uri; - } - catch (Exception ex) - when (ex is ArgumentNullException || ex is UriFormatException) - { - return null; - } - } - } + public string? Url { get; set; } /// /// Gets or sets the string representation of the request method. /// [XmlElement("method")] - public string MethodString { get; set; } + public string? MethodString { get; set; } /// /// Gets the request method. @@ -87,13 +61,13 @@ public HttpMethod Method /// Gets or sets the triggers of the request. /// [XmlElement("triggers")] - public Triggers Triggers { get; set; } + public Triggers? Triggers { get; set; } /// /// Gets or sets the data to send for the request. /// [XmlElement("data")] - public Data Data { get; set; } + public Data? Data { get; set; } /// /// Returns a value indicating if there is a message waiting to be sent @@ -149,25 +123,37 @@ internal void QueueRequest(string message, TriggerType trigger) /// /// Thrown when the URL is null or empty. /// + /// + /// Thrown when the URL is not in a valid format. + /// internal async Task SendAsync() { // If there isn't a message to be sent, then just return if (_message == null || _message.Length <= 0) { - return null; + return new HttpResponseMessage(); } - if (Uri == null) + if (GetUri() == null) { throw new NullReferenceException("The URL is null or empty."); } - string content = Data.Body.Replace("[message]", _message.ToString()); + if (Data == null) + { + throw new NullReferenceException("Data for the request was not provided."); + } + + string content = string.Empty; + if (Data.Body != null) + { + content = Data.Body.Replace("[message]", _message.ToString()); + } HttpResponseMessage response = await Request.SendAsync( Method, - Uri, + GetUri(), Data.Headers, content, Data.MimeType); @@ -186,7 +172,7 @@ await Request.SendAsync( /// /// The JSON string with the special characters escaped. /// - private string CleanMessage(string s) + private static string CleanMessage(string s) { if (s == null || s.Length == 0) { @@ -196,8 +182,8 @@ private string CleanMessage(string s) char c = '\0'; int i; int len = s.Length; - StringBuilder sb = new StringBuilder(len + 4); - String t; + StringBuilder sb = new(len + 4); + string t; for (i = 0; i < len; i += 1) { @@ -231,8 +217,9 @@ private string CleanMessage(string s) default: if (c < ' ') { - t = "000" + String.Format("X", c); - sb.Append("\\u" + t.Substring(t.Length - 4)); + t = "000" + string.Format("{0:X}", c); + sb.Append(string.Concat("\\u", t.AsSpan(t.Length - 4))); + //sb.Append("\\u" + t.Substring(t.Length - 4)); } else { @@ -243,5 +230,22 @@ private string CleanMessage(string s) } return sb.ToString(); } + + /// + /// Gets the URI value of the string URL. + /// + /// + /// Thrown if the URL is not in a valid format. + /// + private Uri GetUri() + { + if (string.IsNullOrWhiteSpace(Url)) + { + throw new UriFormatException(); + } + + Uri uri = new(Url); + return uri; + } } } diff --git a/FileWatcher/Configuration/Notifications/Notifications.cs b/FileWatcher/Configuration/Notifications/Notifications.cs index 4280573..3bbf91c 100644 --- a/FileWatcher/Configuration/Notifications/Notifications.cs +++ b/FileWatcher/Configuration/Notifications/Notifications.cs @@ -23,7 +23,7 @@ public class Notifications private const int MIN_WAIT_TIME = 30000; // The timer - private System.Timers.Timer _timer; + private readonly System.Timers.Timer _timer; /// /// Gets or sets the wait time between notification requests. @@ -84,19 +84,15 @@ private async void OnElapsed(object? source, ElapsedEventArgs e) try { Logger.WriteLine($"Sending the request to {notification.Url}."); - using (HttpResponseMessage response = await notification.SendAsync()) + using HttpResponseMessage response = await notification.SendAsync(); + if (response == null) { - if (response == null) - { - continue; - } - - using (HttpContent httpContent = response.Content) - { - string resultContent = await httpContent.ReadAsStringAsync(); - Logger.WriteLine($"Response: {response.StatusCode}. Content: {resultContent}"); - } + continue; } + + using HttpContent httpContent = response.Content; + string resultContent = await httpContent.ReadAsStringAsync(); + Logger.WriteLine($"Response: {response.StatusCode}. Content: {resultContent}"); } catch (AggregateException aex) { diff --git a/FileWatcher/Configuration/Notifications/Request.cs b/FileWatcher/Configuration/Notifications/Request.cs index 4644129..96d8365 100644 --- a/FileWatcher/Configuration/Notifications/Request.cs +++ b/FileWatcher/Configuration/Notifications/Request.cs @@ -41,9 +41,9 @@ internal enum MimeType // XML mime type private const string MIME_TYPE_XML = "application/xml"; - private static ServiceCollection _services; + private static readonly ServiceCollection _services; - private static ServiceProvider _serviceProvider; + private static readonly ServiceProvider _serviceProvider; static Request() { @@ -76,8 +76,8 @@ static Request() internal static async Task SendAsync( HttpMethod method, Uri uri, - Headers headers, - string body, + Headers? headers, + string? body, MimeType mimeType) { if (uri == null) @@ -85,16 +85,36 @@ internal static async Task SendAsync( throw new ArgumentNullException(nameof(uri)); } - HttpRequestMessage request = new HttpRequestMessage(method, uri); + HttpRequestMessage request = new(method, uri); - headers.Set(request); - request.Content = new StringContent(body, Encoding.UTF8, GetMimeTypeString(mimeType)); + if (headers != null) + { + headers.Set(request); + } + + if (body != null) + { + request.Content = new StringContent(body, Encoding.UTF8, GetMimeTypeString(mimeType)); + } - HttpResponseMessage response = null; + HttpResponseMessage? response = null; try { var client = _serviceProvider.GetService(); - response = await client.SendAsync(request); + if (client != null) + { + response = await client.SendAsync(request); + } + else + { + if (response == null) + { + response = new HttpResponseMessage(); + } + + response.StatusCode = System.Net.HttpStatusCode.InternalServerError; + response.ReasonPhrase = $"Request could not be sent. Reason: The HTTP client service could not be initialized."; + } } catch (Exception ex) { diff --git a/FileWatcher/Configuration/RunnableBase.cs b/FileWatcher/Configuration/RunnableBase.cs index 753701b..54003bd 100644 --- a/FileWatcher/Configuration/RunnableBase.cs +++ b/FileWatcher/Configuration/RunnableBase.cs @@ -60,7 +60,7 @@ public abstract class RunnableBase /// /// The value with the placeholders replaced with the actual strings. /// - protected string ReplacePlaceholders(string value, string watchPath, string fullPath) + protected static string? ReplacePlaceholders(string value, string watchPath, string fullPath) { if (string.IsNullOrWhiteSpace(value) || string.IsNullOrWhiteSpace(watchPath) || string.IsNullOrWhiteSpace(fullPath)) { @@ -68,10 +68,10 @@ protected string ReplacePlaceholders(string value, string watchPath, string full } string relativeFullPath = GetRelativeFullPath(watchPath, fullPath); - string relativePath = GetRelativePath(watchPath, fullPath); - string fileName = GetFilename(fullPath, true); - string fileNameWithoutExtension = GetFilename(fullPath, false); - string extension = GetFileExtension(fullPath); + string? relativePath = GetRelativePath(watchPath, fullPath); + string? fileName = GetFilename(fullPath, true); + string? fileNameWithoutExtension = GetFilename(fullPath, false); + string? extension = GetFileExtension(fullPath); string replacedValue = value; replacedValue = replacedValue.Replace(PLACEHOLDER_EXACTPATH, fullPath); @@ -96,7 +96,7 @@ protected string ReplacePlaceholders(string value, string watchPath, string full /// /// The relative path. /// - private string GetRelativeFullPath(string watchPath, string fullPath) + private static string GetRelativeFullPath(string watchPath, string fullPath) { if (string.IsNullOrWhiteSpace(watchPath) || string.IsNullOrWhiteSpace(fullPath)) { @@ -128,9 +128,14 @@ private string GetRelativeFullPath(string watchPath, string fullPath) /// /// The relative path without the file name, otherwise null. /// - private string GetRelativePath(string watchPath, string fullPath) + private static string? GetRelativePath(string watchPath, string fullPath) { - string relativeFullPath = IO.Path.GetDirectoryName(fullPath); + string? relativeFullPath = IO.Path.GetDirectoryName(fullPath); + if (relativeFullPath == null) + { + return null; + } + return GetRelativeFullPath(watchPath, relativeFullPath); } @@ -143,7 +148,7 @@ private string GetRelativePath(string watchPath, string fullPath) /// /// The name of the file, otherwise null. /// - private string GetFilename(string fullPath, bool includeExtension) + private static string? GetFilename(string fullPath, bool includeExtension) { if (string.IsNullOrEmpty(fullPath) || !IO.File.Exists(fullPath)) { @@ -162,7 +167,7 @@ private string GetFilename(string fullPath, bool includeExtension) /// /// The extension of the full, otherwise null. /// - private string GetFileExtension(string fullPath) + private static string? GetFileExtension(string fullPath) { if (string.IsNullOrEmpty(fullPath) || !IO.File.Exists(fullPath)) { diff --git a/FileWatcher/Configuration/Triggers.cs b/FileWatcher/Configuration/Triggers.cs index da5314c..576ec4a 100644 --- a/FileWatcher/Configuration/Triggers.cs +++ b/FileWatcher/Configuration/Triggers.cs @@ -47,7 +47,7 @@ public class Triggers /// Gets or sets a list of notification triggers. /// [XmlElement("trigger")] - public List TriggerList { get; set; } + public List? TriggerList { get; set; } /// /// Gets the current combined triggers using the list from the diff --git a/FileWatcher/Configuration/Watch.cs b/FileWatcher/Configuration/Watch.cs index 69759fe..f985d72 100644 --- a/FileWatcher/Configuration/Watch.cs +++ b/FileWatcher/Configuration/Watch.cs @@ -19,28 +19,28 @@ namespace TE.FileWatcher.Configuration public class Watch { // The file system watcher object - private FileSystemWatcher _fsWatcher; + private FileSystemWatcher? _fsWatcher; // Information about the last change - private ChangeInfo _lastChange; + private ChangeInfo? _lastChange; // The write time for the last change private DateTime _lastWriteTime; // The timer used to "reset" the FileSystemWatch object - private System.Timers.Timer _timer; + private System.Timers.Timer? _timer; // The background worker that processes the file/folder changes - private BackgroundWorker _worker; + private BackgroundWorker? _worker; // The queue that will contain the changes - private ConcurrentQueue _queue; + private ConcurrentQueue? _queue; /// /// Gets or sets the path of the watch. /// [XmlElement("path")] - public string Path { get; set; } + public string? Path { get; set; } /// /// Gets or sets the timeout value (in seconds) for the watch. @@ -52,31 +52,31 @@ public class Watch /// Gets or sets the filters. /// [XmlElement("filters")] - public Filters.Filters Filters { get; set; } + public Filters.Filters? Filters { get; set; } /// /// Gets or sets the exclusions. /// [XmlElement("exclusions")] - public Exclusions.Exclusions Exclusions { get; set; } + public Exclusions.Exclusions? Exclusions { get; set; } /// /// Gets or sets the notifications for the watch. /// [XmlElement("notifications")] - public Notifications.Notifications Notifications { get; set; } + public Notifications.Notifications? Notifications { get; set; } /// /// Gets or sets the actions for the watch. /// [XmlElement("actions")] - public Actions.Actions Actions { get; set; } + public Actions.Actions? Actions { get; set; } /// /// Gets or sets the commands for the watch. /// [XmlElement("commands")] - public Commands.Commands Commands { get; set; } + public Commands.Commands? Commands { get; set; } /// /// Gets the flag indicating the watch is running. @@ -159,8 +159,10 @@ public bool Stop() /// private void CreateBackgroundWorker() { - _worker = new BackgroundWorker(); - _worker.WorkerSupportsCancellation = false; + _worker = new BackgroundWorker + { + WorkerSupportsCancellation = false + }; _worker.DoWork += DoWork; } @@ -169,19 +171,25 @@ private void CreateBackgroundWorker() /// private void CreateFileSystemWatcher() { - Logger.WriteLine($"Creating watch for {Path}."); + if (string.IsNullOrWhiteSpace(Path)) + { + Logger.WriteLine("The path to watch was not specified."); + return; + } - _fsWatcher = new FileSystemWatcher(Path); + Logger.WriteLine($"Creating watch for {Path}."); - _fsWatcher.NotifyFilter = - NotifyFilters.Attributes - | NotifyFilters.CreationTime - //NotifyFilters.DirectoryName - | NotifyFilters.FileName - //| NotifyFilters.LastAccess - | NotifyFilters.LastWrite - | NotifyFilters.Security - | NotifyFilters.Size; + _fsWatcher = new FileSystemWatcher(Path) + { + NotifyFilter = + NotifyFilters.Attributes + | NotifyFilters.CreationTime + | NotifyFilters.DirectoryName + | NotifyFilters.FileName + | NotifyFilters.LastWrite + | NotifyFilters.Security + | NotifyFilters.Size + }; _fsWatcher.Changed += OnChanged; _fsWatcher.Created += OnCreated; @@ -208,8 +216,10 @@ private void CreateQueue() /// private void CreateTimer() { - _timer = new System.Timers.Timer(600000); - _timer.Enabled = true; + _timer = new System.Timers.Timer(600000) + { + Enabled = true + }; _timer.Elapsed += OnElapsed; } @@ -222,8 +232,13 @@ private void CreateTimer() /// /// Arguments associated with the background worker. /// - private void DoWork(object sender, DoWorkEventArgs e) + private void DoWork(object? sender, DoWorkEventArgs e) { + if (string.IsNullOrWhiteSpace(Path)) + { + return; + } + if (_queue == null) { _queue = new ConcurrentQueue(); @@ -236,59 +251,62 @@ private void DoWork(object sender, DoWorkEventArgs e) while (!_queue.IsEmpty) { - if (_queue.TryDequeue(out ChangeInfo change)) + if (_queue.TryDequeue(out ChangeInfo? change)) { - if (Filters != null && Filters.IsSpecified()) + if (change != null) { - // If the file or folder is not a match, then don't take - // any further actions - if (!Filters.IsMatch(Path, change.Name, change.FullPath)) + if (Filters != null && Filters.IsSpecified()) { - continue; + // If the file or folder is not a match, then don't take + // any further actions + if (!Filters.IsMatch(Path, change.Name, change.FullPath)) + { + continue; + } } - } - if (Exclusions != null && Exclusions.IsSpecified()) - { - // If the file or folder is in the exclude list, then don't - // take any further actions - if (Exclusions.Exclude(Path, change.Name, change.FullPath)) + if (Exclusions != null && Exclusions.IsSpecified()) { - continue; + // If the file or folder is in the exclude list, then don't + // take any further actions + if (Exclusions.Exclude(Path, change.Name, change.FullPath)) + { + continue; + } } - } - if (Notifications != null) - { - if (Notifications.NotificationList != null && Notifications.NotificationList.Count > 0) + if (Notifications != null) { - // Send the notifications - string messageType = GetMessageTypeString(change.Trigger); - if (!string.IsNullOrWhiteSpace(messageType)) + if (Notifications.NotificationList != null && Notifications.NotificationList.Count > 0) { - Notifications.Send(change.Trigger, $"{messageType}: {change.FullPath}"); + // Send the notifications + string? messageType = GetMessageTypeString(change.Trigger); + if (!string.IsNullOrWhiteSpace(messageType)) + { + Notifications.Send(change.Trigger, $"{messageType}: {change.FullPath}"); + } } } - } - if (Actions != null) - { - if (Actions.ActionList != null && Actions.ActionList.Count > 0) + if (Actions != null) { - // Only run the actions if a file wasn't deleted, as the file no - // longer exists so no action can be taken on the file - if (change.Trigger != TriggerType.Delete) + if (Actions.ActionList != null && Actions.ActionList.Count > 0) { - Actions.Run(change.Trigger, Path, change.FullPath); + // Only run the actions if a file wasn't deleted, as the file no + // longer exists so no action can be taken on the file + if (change.Trigger != TriggerType.Delete) + { + Actions.Run(change.Trigger, Path, change.FullPath); + } } } - } - if (Commands != null) - { - if (Commands.CommandList != null && Commands.CommandList.Count > 0) + if (Commands != null) { - Commands.Run(change.Trigger, Path, change.FullPath); + if (Commands.CommandList != null && Commands.CommandList.Count > 0) + { + Commands.Run(change.Trigger, Path, change.FullPath); + } } } } @@ -313,7 +331,7 @@ private void DoWork(object sender, DoWorkEventArgs e) /// /// The object of the change, otherwise null. /// - private ChangeInfo GetChange(TriggerType trigger, string name, string fullPath) + private ChangeInfo? GetChange(TriggerType trigger, string? name, string fullPath) { if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(fullPath)) { @@ -334,7 +352,7 @@ private ChangeInfo GetChange(TriggerType trigger, string name, string fullPath) bool isValid = true; // The current information on the change - ChangeInfo change = new ChangeInfo(trigger, name, fullPath); + ChangeInfo change = new(trigger, name, fullPath); // The last write time of the file DateTime writeTime = default; @@ -395,9 +413,9 @@ private ChangeInfo GetChange(TriggerType trigger, string name, string fullPath) /// /// The string value for the message type, otherwise null. /// - private string GetMessageTypeString(TriggerType trigger) + private static string? GetMessageTypeString(TriggerType trigger) { - string messageType = null; + string? messageType = null; switch (trigger) { case TriggerType.Create: @@ -427,7 +445,7 @@ private string GetMessageTypeString(TriggerType trigger) /// /// The event arguments related to the exception. /// - private void NotAccessibleError(FileSystemWatcher source, ErrorEventArgs e) + private static void NotAccessibleError(FileSystemWatcher source, ErrorEventArgs e) { source.EnableRaisingEvents = false; int iMaxAttempts = 120; @@ -466,7 +484,7 @@ private void OnChanged(object sender, FileSystemEventArgs e) } - ChangeInfo change = GetChange(TriggerType.Change, e.Name, e.FullPath); + ChangeInfo? change = GetChange(TriggerType.Change, e.Name, e.FullPath); if (change != null) { ProcessChange(change); @@ -490,7 +508,7 @@ private void OnCreated(object sender, FileSystemEventArgs e) return; } - ChangeInfo change = GetChange(TriggerType.Create, e.Name, e.FullPath); + ChangeInfo? change = GetChange(TriggerType.Create, e.Name, e.FullPath); if (change != null) { ProcessChange(change); @@ -513,7 +531,7 @@ private void OnDeleted(object sender, FileSystemEventArgs e) return; } - ChangeInfo change = GetChange(TriggerType.Delete, e.Name, e.FullPath); + ChangeInfo? change = GetChange(TriggerType.Delete, e.Name, e.FullPath); if (change != null) { ProcessChange(change); @@ -534,7 +552,7 @@ private void OnDeleted(object sender, FileSystemEventArgs e) /// /// The information associated with the elapsed time. /// - private void OnElapsed(object source, ElapsedEventArgs e) + private void OnElapsed(object? source, ElapsedEventArgs e) { if (_fsWatcher != null) { @@ -559,7 +577,7 @@ private void OnRenamed(object sender, RenamedEventArgs e) return; } - ChangeInfo change = GetChange(TriggerType.Rename, e.Name, e.FullPath); + ChangeInfo? change = GetChange(TriggerType.Rename, e.Name, e.FullPath); if (change != null) { ProcessChange(change); diff --git a/FileWatcher/Configuration/Watches.cs b/FileWatcher/Configuration/Watches.cs index 0c00756..d23588b 100644 --- a/FileWatcher/Configuration/Watches.cs +++ b/FileWatcher/Configuration/Watches.cs @@ -24,13 +24,18 @@ public class Watches /// Gets or sets the watches list. /// [XmlElement("watch")] - public List WatchList { get; set; } + public List? WatchList { get; set; } /// /// Starts the watches. /// public void Start() { + if (WatchList == null) + { + return; + } + foreach (Watch watch in WatchList) { try diff --git a/FileWatcher/Configuration/XmlFile.cs b/FileWatcher/Configuration/XmlFile.cs index 908c655..d7e4470 100644 --- a/FileWatcher/Configuration/XmlFile.cs +++ b/FileWatcher/Configuration/XmlFile.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -16,7 +17,7 @@ public class XmlFile : IConfigurationFile public const string DEFAULT_CONFIG_FILE = "config.xml"; // Path to the configuration file - private string _fullPath; + private readonly string? _fullPath; /// /// Initializes an instance of the class when @@ -48,13 +49,13 @@ public XmlFile(string path, string name) /// /// The folder path of the files, otherwise null. /// - private string GetFolderPath(string path) + private static string? GetFolderPath(string? path) { if (string.IsNullOrWhiteSpace(path)) { try { - path = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); + path = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule?.FileName); } catch (Exception ex) { @@ -86,9 +87,9 @@ private string GetFolderPath(string path) /// /// The full path to the configuration file, otherwise null. /// - private string GetFullPath(string path, string name) + private static string? GetFullPath(string path, string name) { - string folderPath = GetFolderPath(path); + string? folderPath = GetFolderPath(path); if (folderPath == null) { return null; @@ -127,7 +128,8 @@ private string GetFullPath(string path, string name) /// A object if the file was read successfully, /// otherwise null. /// - public Watches Read() + [RequiresUnreferencedCode("Calls XmlSerializer")] + public Watches? Read() { if (string.IsNullOrWhiteSpace(_fullPath)) { @@ -143,9 +145,9 @@ public Watches Read() try { - XmlSerializer serializer = new XmlSerializer(typeof(Watches)); - using FileStream fs = new FileStream(_fullPath, FileMode.Open); - return (Watches)serializer.Deserialize(fs); + XmlSerializer serializer = new(typeof(Watches)); + using FileStream fs = new(_fullPath, FileMode.Open); + return (Watches?)serializer.Deserialize(fs); } catch (Exception ex) { diff --git a/FileWatcher/FileSystem/Directory.cs b/FileWatcher/FileSystem/Directory.cs index 324f8f5..0313e98 100644 --- a/FileWatcher/FileSystem/Directory.cs +++ b/FileWatcher/FileSystem/Directory.cs @@ -25,13 +25,16 @@ public static void Create(string path) return; } - string folders = IO.Path.GetDirectoryName(path); + string? folders = Path.GetDirectoryName(path); - // If the destination directory doesn't exist, create - // create it to avoid any exceptions - if (!IO.Directory.Exists(folders)) + if (!string.IsNullOrWhiteSpace(folders)) { - IO.Directory.CreateDirectory(folders); + // If the destination directory doesn't exist, create + // create it to avoid any exceptions + if (!IO.Directory.Exists(folders)) + { + IO.Directory.CreateDirectory(folders); + } } } diff --git a/FileWatcher/FileSystem/File.cs b/FileWatcher/FileSystem/File.cs index 2c3a72e..8eb681b 100644 --- a/FileWatcher/FileSystem/File.cs +++ b/FileWatcher/FileSystem/File.cs @@ -19,7 +19,7 @@ public static class File private const int RETRIES = 5; // The hash algorithm to use when verifying the files - private const string HASH_ALGORITHM = "SHA256"; + //private const string HASH_ALGORITHM = "SHA256"; /// /// Gets the hash of the file. @@ -30,18 +30,19 @@ public static class File /// /// The hash of the file, otherwise null. /// - private static string GetFileHash(string fullPath) + private static string? GetFileHash(string fullPath) { try { - using (var hashAlgorithm = HashAlgorithm.Create(HASH_ALGORITHM)) + using var hashAlgorithm = SHA256.Create(); + if (hashAlgorithm == null) { - using (var stream = IO.File.OpenRead(fullPath)) - { - var hash = hashAlgorithm.ComputeHash(stream); - return BitConverter.ToString(hash).Replace("-", ""); - } + return null; } + + using var stream = IO.File.OpenRead(fullPath); + var hash = hashAlgorithm.ComputeHash(stream); + return BitConverter.ToString(hash).Replace("-", ""); } catch { @@ -64,14 +65,19 @@ private static string GetFileHash(string fullPath) /// private static bool Verify(string source, string destination) { - string sourceHash = GetFileHash(source); - string destinationHash = GetFileHash(destination); - if (string.IsNullOrWhiteSpace(source) || string.IsNullOrWhiteSpace(destination)) { return false; } + string? sourceHash = GetFileHash(source); + string? destinationHash = GetFileHash(destination); + + if (string.IsNullOrWhiteSpace(sourceHash)) + { + return false; + } + return (sourceHash.Equals(destinationHash)); } @@ -176,7 +182,7 @@ public static void Copy(string source, string destination, bool verify) /// /// true if the file is valid, otherwise false. /// - public static bool IsValid(string path) + public static bool IsValid(string? path) { if (string.IsNullOrWhiteSpace(path)) { diff --git a/FileWatcher/FileWatcher.csproj b/FileWatcher/FileWatcher.csproj index 77d5240..388afd6 100644 --- a/FileWatcher/FileWatcher.csproj +++ b/FileWatcher/FileWatcher.csproj @@ -18,8 +18,8 @@ Monitor folders and files on the local system for changes. ©2022 https://github.com/TechieGuy12/FileWatcher - 1.2.1.0 - 1.2.1.0 + 1.2.2.0 + 1.2.2.0 filesystem file-monitoring folder-monitoring diff --git a/FileWatcher/Logging/Logger.cs b/FileWatcher/Logging/Logger.cs index 806f433..d01d002 100644 --- a/FileWatcher/Logging/Logger.cs +++ b/FileWatcher/Logging/Logger.cs @@ -46,7 +46,7 @@ public static class Logger private const int MEGABYTE = 1048576; // The queue of log messages - private static ConcurrentQueue queue; + private static readonly ConcurrentQueue queue; /// /// Gets the path to the log. @@ -75,7 +75,7 @@ public static class Logger public static int LogNumber { get; set; } // The object used for the lock - private static object locker = new object(); + private static readonly object locker = new(); /// /// Initializes an instance of the class. @@ -83,7 +83,9 @@ public static class Logger /// /// Thrown when the logger could not be initialized. /// +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. static Logger() +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { LogPath = Path.GetTempPath(); LogName = DEFAULT_LOG_NAME; @@ -111,7 +113,16 @@ static Logger() /// public static void SetLogger(Configuration.Logging logOptions) { - SetFullPath(logOptions.LogPath); + if (logOptions == null) + { + return; + } + + if (!string.IsNullOrWhiteSpace(logOptions.LogPath)) + { + SetFullPath(logOptions.LogPath); + } + LogSize = logOptions.Size; LogNumber = logOptions.Number; } @@ -163,12 +174,12 @@ private static void SetFullPath(string logPath, string logName) { if (string.IsNullOrWhiteSpace(logPath)) { - throw new ArgumentNullException("The logPath argument is null or empty."); + throw new ArgumentNullException(nameof(logPath)); } if (string.IsNullOrWhiteSpace(logName)) { - throw new ArgumentNullException("The logName argument is null or empty."); + throw new ArgumentNullException(nameof(logName)); } string fullPath = Path.Combine(logPath, logName); @@ -192,12 +203,12 @@ private static void SetFullPath(string fullPath) { if (string.IsNullOrWhiteSpace(fullPath)) { - throw new ArgumentNullException("The fullPath argument is null or empty."); + throw new ArgumentNullException(nameof(fullPath)); } // Separate the path and log name so each can be check to ensure // they are valid - string path = Path.GetDirectoryName(fullPath); + string? path = Path.GetDirectoryName(fullPath); string name = Path.GetFileName(fullPath); if (!IsFolderValid(path)) @@ -210,10 +221,19 @@ private static void SetFullPath(string fullPath) throw new IOException($"The log file name '{name}' is not valid"); } - // Store the path, name and the full path if all the checks pass - LogPath = path; - LogName = name; - LogFullPath = Path.Combine(path, name); + if (!string.IsNullOrWhiteSpace(path)) + { + // Store the path, name and the full path if all the checks pass + LogPath = path; + LogName = name; + LogFullPath = Path.Combine(path, name); + } + else + { + LogPath = string.Empty; + LogName = name; + LogFullPath = string.Empty; + } } /// @@ -226,7 +246,7 @@ private static void SetFullPath(string fullPath) /// /// True if the folder is valid and exists, otherwise false. /// - private static bool IsFolderValid(string folder) + private static bool IsFolderValid(string? folder) { if (string.IsNullOrWhiteSpace(folder)) { @@ -299,7 +319,7 @@ private static void RolloverLog() { // Get and check the log size to see if it is still less than the // specified log size - FileInfo fileInfo = new FileInfo(LogFullPath); + FileInfo fileInfo = new(LogFullPath); if (fileInfo.Length < (LogSize * MEGABYTE)) { return; @@ -339,22 +359,20 @@ private static void RolloverLog() /// private static void WriteToLog() { - while (queue.TryDequeue(out Message message)) + while (queue.TryDequeue(out Message? message)) { try { lock (locker) { RolloverLog(); - using (StreamWriter writer = new StreamWriter(LogFullPath, true)) - { - writer.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {message.LevelString} {message.Value}"); - } + using StreamWriter writer = new(LogFullPath, true); + writer.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {message.LevelString} {message.Value}"); } } catch (Exception ex) { - Message error = new Message($"Couldn't write to the log. Reason: {ex.Message}", LogLevel.WARNING); + Message error = new($"Couldn't write to the log. Reason: {ex.Message}", LogLevel.WARNING); Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {error.LevelString} {error.Value}"); } } diff --git a/FileWatcher/Program.cs b/FileWatcher/Program.cs index 6b51964..d9b23fa 100644 --- a/FileWatcher/Program.cs +++ b/FileWatcher/Program.cs @@ -1,6 +1,7 @@ using System; using System.CommandLine; using System.CommandLine.Invocation; +using System.Diagnostics.CodeAnalysis; using TE.FileWatcher.Configuration; using TE.FileWatcher.Logging; @@ -26,9 +27,10 @@ class Program /// /// Returns 0 on success, otherwise non-zero. /// + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] static int Main(string[] args) { - RootCommand rootCommand = new RootCommand + RootCommand rootCommand = new() { new Option( aliases: new string[] { "--folder", "-f" }, @@ -56,12 +58,13 @@ static int Main(string[] args) /// /// Returns 0 if no error occurred, otherwise non-zero. /// + [RequiresUnreferencedCode("Calls TE.FileWatcher.Configuration.IConfigurationFile.Read()")] private static int Run(string folder, string configFile) { IConfigurationFile config = new XmlFile(folder, configFile); // Load the watches information from the config XML file - Watches watches = config.Read(); + Watches? watches = config.Read(); if (watches == null) { return ERROR;