From 7065b0c567b6ad4abf22e5cf631b804012107ce2 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Mon, 16 Apr 2018 16:54:03 -0400 Subject: [PATCH 01/10] feat: Adding util methods for path comparisons --- ICD.Common.Utils/IO/IcdPath.cs | 4 ++ ICD.Common.Utils/PathUtils.cs | 18 +++++++++ ICD.Common.Utils/StringUtils.cs | 72 +++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/ICD.Common.Utils/IO/IcdPath.cs b/ICD.Common.Utils/IO/IcdPath.cs index 37d0bad..6ee4a52 100644 --- a/ICD.Common.Utils/IO/IcdPath.cs +++ b/ICD.Common.Utils/IO/IcdPath.cs @@ -10,6 +10,10 @@ namespace ICD.Common.Utils.IO { public static class IcdPath { + public static char DirectorySeparatorChar { get { return Path.DirectorySeparatorChar; } } + + public static char AltDirectorySeparatorChar { get { return Path.AltDirectorySeparatorChar; } } + public static string GetFileName(string path) { if (path == null) diff --git a/ICD.Common.Utils/PathUtils.cs b/ICD.Common.Utils/PathUtils.cs index 7a691e1..3d473a6 100644 --- a/ICD.Common.Utils/PathUtils.cs +++ b/ICD.Common.Utils/PathUtils.cs @@ -185,6 +185,24 @@ namespace ICD.Common.Utils return IcdFile.Exists(path) || IcdDirectory.Exists(path); } + /// + /// Returns the path if the given path is already a directory or has a trailing slash. + /// Otherwise returns the parent directory name. + /// + /// + /// + [PublicAPI] + public static string GetDirectoryNameFromPath(string path) + { + if (IcdDirectory.Exists(path)) + return path; + + if (path.EndsWith(IcdPath.DirectorySeparatorChar) || path.EndsWith(IcdPath.AltDirectorySeparatorChar)) + return path; + + return IcdPath.GetDirectoryName(path); + } + #endregion } } diff --git a/ICD.Common.Utils/StringUtils.cs b/ICD.Common.Utils/StringUtils.cs index 36008e7..3235b7b 100644 --- a/ICD.Common.Utils/StringUtils.cs +++ b/ICD.Common.Utils/StringUtils.cs @@ -610,5 +610,77 @@ namespace ICD.Common.Utils { return value == null ? null : value.ToUpper(); } + + /// + /// Compares the given chars for equality. + /// + /// + /// + /// + /// + [PublicAPI] + public static bool Compare(char a, char b, bool ignoreCase) + { + if (ignoreCase) + { + a = char.ToUpper(a, CultureInfo.InvariantCulture); + b = char.ToUpper(b, CultureInfo.InvariantCulture); + } + + return a == b; + } + + /// + /// Find the longest common string between the matches. + /// E.g. + /// + /// C:\\Workspace + /// C:\\Workshop + /// + /// Results in + /// + /// C:\\Work + /// + /// + /// + /// + [PublicAPI] + public static string GetLongestCommonIntersectionFromStart(IEnumerable items, bool ignoreCase) + { + if (items == null) + throw new ArgumentNullException("items"); + + string output = null; + + foreach (string item in items) + { + // If there is a null in the sequence that's the best match we can make + if (string.IsNullOrEmpty(item)) + return null; + + // Seed our first item + if (output == null) + { + output = item; + continue; + } + + // Find the common substring + for (int index = 0; index < output.Length; index++) + { + if (index >= item.Length || !Compare(output[index], item[index], ignoreCase)) + { + output = output.Substring(0, index); + break; + } + } + + // Abandon the search if there is no common substring + if (string.IsNullOrEmpty(output)) + break; + } + + return output; + } } } From 23047c1c2c4a6e816bdb93e8b2bda2ca95f562e4 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Tue, 17 Apr 2018 14:05:11 -0400 Subject: [PATCH 02/10] docs: Fixing comment --- ICD.Common.Utils/Extensions/ListExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICD.Common.Utils/Extensions/ListExtensions.cs b/ICD.Common.Utils/Extensions/ListExtensions.cs index e5394a8..68642f9 100644 --- a/ICD.Common.Utils/Extensions/ListExtensions.cs +++ b/ICD.Common.Utils/Extensions/ListExtensions.cs @@ -29,7 +29,7 @@ namespace ICD.Common.Utils.Extensions } /// - /// Adds the item into a sorted list. + /// Adds the items into a sorted list. /// /// /// From 9e715d37904dd9cf8d7d6b14a522120767e9c518 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Tue, 17 Apr 2018 14:05:32 -0400 Subject: [PATCH 03/10] feat: Util methods for inserting items into a sorted list by a predicate --- ICD.Common.Utils/Extensions/ListExtensions.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/ICD.Common.Utils/Extensions/ListExtensions.cs b/ICD.Common.Utils/Extensions/ListExtensions.cs index 68642f9..50c28c7 100644 --- a/ICD.Common.Utils/Extensions/ListExtensions.cs +++ b/ICD.Common.Utils/Extensions/ListExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using ICD.Common.Properties; +using ICD.Common.Utils.Comparers; namespace ICD.Common.Utils.Extensions { @@ -50,6 +51,30 @@ namespace ICD.Common.Utils.Extensions items.ForEach(i => extends.AddSorted(i, comparer)); } + /// + /// Adds the items into a sorted list. + /// + /// + /// + /// + /// + /// + [PublicAPI] + public static void AddSorted(this List extends, IEnumerable items, Func predicate) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + if (items == null) + throw new ArgumentNullException("items"); + + if (predicate == null) + throw new ArgumentNullException("predicate"); + + PredicateComparer comparer = new PredicateComparer(predicate); + extends.AddSorted(items, comparer); + } + /// /// Adds the item into a sorted list. /// @@ -106,6 +131,27 @@ namespace ICD.Common.Utils.Extensions extends.Insert(index, item); } + /// + /// Adds the item into a sorted list. + /// + /// + /// + /// + /// + /// + [PublicAPI] + public static void AddSorted(this List extends, T item, Func predicate) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + if (predicate == null) + throw new ArgumentNullException("predicate"); + + PredicateComparer comparer = new PredicateComparer(predicate); + extends.AddSorted(item, comparer); + } + /// /// Pads the list to the given total length. /// From d587b794cbe7ee3fadf02a6457f177c6f62316a3 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Wed, 18 Apr 2018 14:12:21 -0400 Subject: [PATCH 04/10] feat: Adding extension method for getting assembly informational version --- CHANGELOG.md | 5 +++++ ICD.Common.Utils/Extensions/AssemblyExtensions.cs | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 825f45d..3a11e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,3 +3,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] +### Added + - Adding extension method for getting Informational Version from an Assembly + \ No newline at end of file diff --git a/ICD.Common.Utils/Extensions/AssemblyExtensions.cs b/ICD.Common.Utils/Extensions/AssemblyExtensions.cs index 3a67c37..0cb0615 100644 --- a/ICD.Common.Utils/Extensions/AssemblyExtensions.cs +++ b/ICD.Common.Utils/Extensions/AssemblyExtensions.cs @@ -57,5 +57,18 @@ namespace ICD.Common.Utils.Extensions string path = extends.GetPath(); return path == null ? DateTime.MinValue : IcdFile.GetCreationTime(path); } + + /// + /// Gets the informational version for the given assembly. + /// + /// + /// + public static string GetInformationalVersion(this Assembly extends) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + return extends.GetCustomAttribute().InformationalVersion; + } } } From 2bd018b7f1522260ff0bbe98214a94aaeb32b9f1 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Thu, 19 Apr 2018 15:54:27 -0400 Subject: [PATCH 05/10] docs: Tidying comments --- ICD.Common.Utils/Extensions/AssemblyExtensions.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ICD.Common.Utils/Extensions/AssemblyExtensions.cs b/ICD.Common.Utils/Extensions/AssemblyExtensions.cs index 0cb0615..373d344 100644 --- a/ICD.Common.Utils/Extensions/AssemblyExtensions.cs +++ b/ICD.Common.Utils/Extensions/AssemblyExtensions.cs @@ -12,7 +12,7 @@ namespace ICD.Common.Utils.Extensions public static class AssemblyExtensions { /// - /// Gets the path for the given assembly. Returns null if the assembly can not be found on disk. + /// Gets the path for the assembly. Returns null if the assembly can not be found on disk. /// /// /// @@ -45,10 +45,11 @@ namespace ICD.Common.Utils.Extensions } /// - /// Gets the creation date of the given assembly. + /// Gets the creation date of the assembly. /// /// /// + [PublicAPI] public static DateTime GetCreationTime(this Assembly extends) { if (extends == null) @@ -59,10 +60,11 @@ namespace ICD.Common.Utils.Extensions } /// - /// Gets the informational version for the given assembly. + /// Gets the informational version for the assembly. /// /// /// + [PublicAPI] public static string GetInformationalVersion(this Assembly extends) { if (extends == null) From f8d189564ad8f6ac873b8ebde267e3a21fc5bc0a Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Thu, 19 Apr 2018 15:55:01 -0400 Subject: [PATCH 06/10] feat: TryGetInformationalVersion extension method --- .../Extensions/AssemblyExtensions.cs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/ICD.Common.Utils/Extensions/AssemblyExtensions.cs b/ICD.Common.Utils/Extensions/AssemblyExtensions.cs index 373d344..fafd5a9 100644 --- a/ICD.Common.Utils/Extensions/AssemblyExtensions.cs +++ b/ICD.Common.Utils/Extensions/AssemblyExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using ICD.Common.Properties; using ICD.Common.Utils.IO; #if SIMPLSHARP @@ -70,7 +71,28 @@ namespace ICD.Common.Utils.Extensions if (extends == null) throw new ArgumentNullException("extends"); - return extends.GetCustomAttribute().InformationalVersion; + string version; + if (extends.TryGetInformationalVersion(out version)) + return version; + + throw new InvalidOperationException("Assembly has no informational version attribute."); + } + + /// + /// Tries to get the informational version for the assembly. + /// + /// + /// + /// + [PublicAPI] + public static bool TryGetInformationalVersion(this Assembly extends, out string version) + { + if (extends == null) + throw new ArgumentNullException("extends"); + + return extends.GetCustomAttributes() + .Select(a => a.InformationalVersion) + .TryFirst(out version); } } } From 3876c0470fea56e5a7c7dafd972f950ea6dc6b40 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Fri, 20 Apr 2018 17:30:49 -0400 Subject: [PATCH 07/10] refactor: Reducing redundant code by moving json serialization/deserialization features into abstract converter --- CHANGELOG.md | 3 + .../Json/AbstractGenericJsonConverter.cs | 75 ++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a11e17..a320b05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,4 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Added - Adding extension method for getting Informational Version from an Assembly + +### Changed + - JSON serialization/deserialization features moved into base converter \ No newline at end of file diff --git a/ICD.Common.Utils/Json/AbstractGenericJsonConverter.cs b/ICD.Common.Utils/Json/AbstractGenericJsonConverter.cs index 151a7ca..ced8956 100644 --- a/ICD.Common.Utils/Json/AbstractGenericJsonConverter.cs +++ b/ICD.Common.Utils/Json/AbstractGenericJsonConverter.cs @@ -6,6 +6,15 @@ namespace ICD.Common.Utils.Json { public abstract class AbstractGenericJsonConverter : JsonConverter { + /// + /// Creates a new instance of T. + /// + /// + protected virtual T Instantiate() + { + return ReflectionUtils.CreateInstance(); + } + /// /// Writes the JSON representation of the object. /// @@ -36,7 +45,24 @@ namespace ICD.Common.Utils.Json /// The value. /// The calling serializer. [PublicAPI] - public abstract void WriteJson(JsonWriter writer, T value, JsonSerializer serializer); + public virtual void WriteJson(JsonWriter writer, T value, JsonSerializer serializer) + { + writer.WriteStartObject(); + { + WriteProperties(writer, value, serializer); + } + writer.WriteEndObject(); + } + + /// + /// Override to write properties to the writer. + /// + /// + /// + /// + protected virtual void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer) + { + } /// /// Reads the JSON representation of the object. @@ -70,7 +96,52 @@ namespace ICD.Common.Utils.Json /// The object value. /// [PublicAPI] - public abstract T ReadJson(JsonReader reader, T existingValue, JsonSerializer serializer); + public virtual T ReadJson(JsonReader reader, T existingValue, JsonSerializer serializer) + { + T output = default(T); + bool instantiated = false; + + while (reader.Read()) + { + if (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.EndObject) + break; + + if (!instantiated) + { + instantiated = true; + output = Instantiate(); + } + + // Get the property + if (reader.TokenType != JsonToken.PropertyName) + continue; + string property = (string)reader.Value; + + // Read into the value + reader.Read(); + + switch (property) + { + default: + ReadProperty(property, reader, output, serializer); + break; + } + } + + return output; + } + + /// + /// Override to handle the current property value with the given name. + /// + /// + /// + /// + /// + protected virtual void ReadProperty(string property, JsonReader reader, T instance, JsonSerializer serializer) + { + reader.Skip(); + } /// /// Determines whether this instance can convert the specified object type. From 7b8ae8402e515d0a3f9cb0acb57c3aa56f5c37e1 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Mon, 23 Apr 2018 14:06:02 -0400 Subject: [PATCH 08/10] chore: Updating changelog and major version number --- CHANGELOG.md | 5 +++++ ICD.Common.Utils/Properties/AssemblyInfo.cs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a320b05..65ec3d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [3.0.0] - 2018-04-23 ### Added - Adding extension method for getting Informational Version from an Assembly + - Adding WeakKeyDictionary for caching + - Reflection util methods ### Changed - JSON serialization/deserialization features moved into base converter + - Removed suffix from assembly name \ No newline at end of file diff --git a/ICD.Common.Utils/Properties/AssemblyInfo.cs b/ICD.Common.Utils/Properties/AssemblyInfo.cs index 4a435e7..2303f51 100644 --- a/ICD.Common.Utils/Properties/AssemblyInfo.cs +++ b/ICD.Common.Utils/Properties/AssemblyInfo.cs @@ -4,4 +4,4 @@ using System.Reflection; [assembly: AssemblyCompany("ICD Systems")] [assembly: AssemblyProduct("ICD.Common.Utils")] [assembly: AssemblyCopyright("Copyright © ICD Systems 2018")] -[assembly: AssemblyVersion("2.0.0.0")] +[assembly: AssemblyVersion("3.0.0.0")] From 08f525eb3efc38bb21058a5e9ca71b108c816dcc Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Wed, 25 Apr 2018 14:09:09 -0400 Subject: [PATCH 09/10] feat: Clearer log message for failing to cache assembly --- ICD.Common.Utils/AttributeUtils.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ICD.Common.Utils/AttributeUtils.cs b/ICD.Common.Utils/AttributeUtils.cs index e9cf173..2cd9943 100644 --- a/ICD.Common.Utils/AttributeUtils.cs +++ b/ICD.Common.Utils/AttributeUtils.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using ICD.Common.Properties; using ICD.Common.Utils.Collections; @@ -84,6 +85,14 @@ namespace ICD.Common.Utils { foreach (Exception inner in e.LoaderExceptions) { + if (inner is FileNotFoundException) + { + Logger.AddEntry(eSeverity.Error, + "{0} failed to cache assembly {1} - Could not find one or more dependencies by path", + typeof(AttributeUtils).Name, assembly.GetName().Name); + continue; + } + Logger.AddEntry(eSeverity.Error, inner, "{0} failed to cache assembly {1}", typeof(AttributeUtils).Name, assembly.GetName().Name); } From a5cc9e694afc29943075443354b67b106c88e9ab Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Thu, 26 Apr 2018 11:05:49 -0400 Subject: [PATCH 10/10] refactor: Tidying --- ICD.Common.Utils/AttributeUtils.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ICD.Common.Utils/AttributeUtils.cs b/ICD.Common.Utils/AttributeUtils.cs index 2cd9943..637b8cc 100644 --- a/ICD.Common.Utils/AttributeUtils.cs +++ b/ICD.Common.Utils/AttributeUtils.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using ICD.Common.Properties; using ICD.Common.Utils.Collections; @@ -85,7 +84,7 @@ namespace ICD.Common.Utils { foreach (Exception inner in e.LoaderExceptions) { - if (inner is FileNotFoundException) + if (inner is System.IO.FileNotFoundException) { Logger.AddEntry(eSeverity.Error, "{0} failed to cache assembly {1} - Could not find one or more dependencies by path",