From 5b94ad7cff1bb4dd699fb45445673fd64a178958 Mon Sep 17 00:00:00 2001 From: Richard Webb Date: Sun, 31 Dec 2023 14:22:26 +0000 Subject: [PATCH] Experiment: Separate out the System.Configuration.ConfigurationManager support --- Argu.sln | 20 +++++--- .../Argu.ConfigurationManager.fsproj | 25 ++++++++++ src/Argu.ConfigurationManager/Library.fs | 49 +++++++++++++++++++ src/Argu/Argu.fsproj | 2 - src/Argu/ArgumentParser.fs | 2 +- src/Argu/ConfigReaders.fs | 39 --------------- tests/Argu.Tests/Argu.Tests.fsproj | 15 +++--- 7 files changed, 96 insertions(+), 56 deletions(-) create mode 100644 src/Argu.ConfigurationManager/Argu.ConfigurationManager.fsproj create mode 100644 src/Argu.ConfigurationManager/Library.fs diff --git a/Argu.sln b/Argu.sln index ec908371..4dc5de62 100644 --- a/Argu.sln +++ b/Argu.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2002 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 MinimumVisualStudioVersion = 10.0.40219.1 Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Argu", "src\Argu\Argu.fsproj", "{D3E958F9-5FFF-462E-BDC7-A03272A9F5D9}" EndProject @@ -62,32 +62,38 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resource", "resource", "{B1 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{A15390A5-BC39-433F-BA25-8775B4C2E329}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Argu.ConfigurationManager", "src\Argu.ConfigurationManager\Argu.ConfigurationManager.fsproj", "{0EA62775-1A5D-46CD-A21B-2120BA73FBF5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E0563A30-4451-4DF2-9D21-26C76EB85C22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E0563A30-4451-4DF2-9D21-26C76EB85C22}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E0563A30-4451-4DF2-9D21-26C76EB85C22}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E0563A30-4451-4DF2-9D21-26C76EB85C22}.Release|Any CPU.Build.0 = Release|Any CPU {D3E958F9-5FFF-462E-BDC7-A03272A9F5D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D3E958F9-5FFF-462E-BDC7-A03272A9F5D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {D3E958F9-5FFF-462E-BDC7-A03272A9F5D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {D3E958F9-5FFF-462E-BDC7-A03272A9F5D9}.Release|Any CPU.Build.0 = Release|Any CPU + {E0563A30-4451-4DF2-9D21-26C76EB85C22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0563A30-4451-4DF2-9D21-26C76EB85C22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0563A30-4451-4DF2-9D21-26C76EB85C22}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0563A30-4451-4DF2-9D21-26C76EB85C22}.Release|Any CPU.Build.0 = Release|Any CPU {8E234746-5098-4400-98F1-62C77AB91711}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8E234746-5098-4400-98F1-62C77AB91711}.Debug|Any CPU.Build.0 = Debug|Any CPU {8E234746-5098-4400-98F1-62C77AB91711}.Release|Any CPU.ActiveCfg = Release|Any CPU {8E234746-5098-4400-98F1-62C77AB91711}.Release|Any CPU.Build.0 = Release|Any CPU + {0EA62775-1A5D-46CD-A21B-2120BA73FBF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0EA62775-1A5D-46CD-A21B-2120BA73FBF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0EA62775-1A5D-46CD-A21B-2120BA73FBF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0EA62775-1A5D-46CD-A21B-2120BA73FBF5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {E0563A30-4451-4DF2-9D21-26C76EB85C22} = {A15390A5-BC39-433F-BA25-8775B4C2E329} {EE42293D-9398-4EF4-B151-9DE992EBB85A} = {83FE66F8-6E59-4178-8962-11117B51F39C} {10ED3503-22F2-42EF-8B35-C979A5B700D0} = {C9E28045-41C6-422E-9928-4220EF3FF19B} - {E0563A30-4451-4DF2-9D21-26C76EB85C22} = {A15390A5-BC39-433F-BA25-8775B4C2E329} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {99215464-9AB5-4BC3-A033-92EA250F8FC1} diff --git a/src/Argu.ConfigurationManager/Argu.ConfigurationManager.fsproj b/src/Argu.ConfigurationManager/Argu.ConfigurationManager.fsproj new file mode 100644 index 00000000..7e7a5d7d --- /dev/null +++ b/src/Argu.ConfigurationManager/Argu.ConfigurationManager.fsproj @@ -0,0 +1,25 @@ + + + + netstandard2.0 + true + + + + + + + + + + + + + + + + + + + + diff --git a/src/Argu.ConfigurationManager/Library.fs b/src/Argu.ConfigurationManager/Library.fs new file mode 100644 index 00000000..d626a1e7 --- /dev/null +++ b/src/Argu.ConfigurationManager/Library.fs @@ -0,0 +1,49 @@ +namespace Argu + +open System.Configuration +open System.IO + +/// AppSettings XML configuration reader +type AppSettingsConfigurationReader () = + interface IConfigurationReader with + member _.Name = "AppSettings configuration reader" + member _.GetValue(key:string) = ConfigurationManager.AppSettings[key] + +/// AppSettings XML configuration reader +type AppSettingsConfigurationFileReader private (xmlPath : string, kv : KeyValueConfigurationCollection) = + member _.Path = xmlPath + interface IConfigurationReader with + member _.Name = sprintf "App.config configuration reader: %s" xmlPath + member _.GetValue(key:string) = + match kv[key] with + | null -> null + | entry -> entry.Value + + /// Create used supplied XML file path + static member Create(path : string) = + if not <| File.Exists path then raise <| FileNotFoundException(path) + let fileMap = ExeConfigurationFileMap() + fileMap.ExeConfigFilename <- path + let config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None) + AppSettingsConfigurationFileReader(path, config.AppSettings.Settings) + +[] +module ConfigurationReaderExtensions = + open System.Reflection + open System + + /// Configuration reader implementations + type ConfigurationReader with + + /// Create a configuration reader instance using the application's resident AppSettings configuration + static member FromAppSettings() = AppSettingsConfigurationReader() :> IConfigurationReader + /// Create a configuration reader instance using a local xml App.Config file + static member FromAppSettingsFile(path : string) = AppSettingsConfigurationFileReader.Create(path) :> IConfigurationReader + /// Create a configuration reader instance using the location of an assembly file + static member FromAppSettings(assembly : Assembly) = + let path = assembly.Location + if String.IsNullOrEmpty path then + sprintf "Assembly location for '%O' is null or empty." assembly.Location + |> invalidArg assembly.FullName + + AppSettingsConfigurationFileReader.Create(path + ".config") :> IConfigurationReader diff --git a/src/Argu/Argu.fsproj b/src/Argu/Argu.fsproj index 50ef4cce..6eab57bb 100644 --- a/src/Argu/Argu.fsproj +++ b/src/Argu/Argu.fsproj @@ -25,7 +25,5 @@ - - \ No newline at end of file diff --git a/src/Argu/ArgumentParser.fs b/src/Argu/ArgumentParser.fs index cfc3ce47..fad94e11 100644 --- a/src/Argu/ArgumentParser.fs +++ b/src/Argu/ArgumentParser.fs @@ -171,7 +171,7 @@ and [] let configurationReader = match configurationReader with | Some c -> c - | None -> ConfigurationReader.FromAppSettings() + | None -> ConfigurationReader.NullReader try let appSettingsResults = parseKeyValueConfig configurationReader argInfo diff --git a/src/Argu/ConfigReaders.fs b/src/Argu/ConfigReaders.fs index bbc6643a..8176a136 100644 --- a/src/Argu/ConfigReaders.fs +++ b/src/Argu/ConfigReaders.fs @@ -1,10 +1,7 @@ namespace Argu open System -open System.IO -open System.Configuration open System.Collections.Generic -open System.Reflection /// Abstract key/value configuration reader type IConfigurationReader = @@ -56,30 +53,6 @@ type FunctionConfigurationReader (configFunc : string -> string option, ?name : | None -> null | Some v -> v -/// AppSettings XML configuration reader -type AppSettingsConfigurationReader () = - interface IConfigurationReader with - member _.Name = "AppSettings configuration reader" - member _.GetValue(key:string) = ConfigurationManager.AppSettings[key] - -/// AppSettings XML configuration reader -type AppSettingsConfigurationFileReader private (xmlPath : string, kv : KeyValueConfigurationCollection) = - member _.Path = xmlPath - interface IConfigurationReader with - member _.Name = sprintf "App.config configuration reader: %s" xmlPath - member _.GetValue(key:string) = - match kv[key] with - | null -> null - | entry -> entry.Value - - /// Create used supplied XML file path - static member Create(path : string) = - if not <| File.Exists path then raise <| FileNotFoundException(path) - let fileMap = ExeConfigurationFileMap() - fileMap.ExeConfigFilename <- path - let config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None) - AppSettingsConfigurationFileReader(path, config.AppSettings.Settings) - /// Configuration reader implementations type ConfigurationReader = /// Create a configuration reader that always returns null @@ -97,15 +70,3 @@ type ConfigurationReader = static member FromEnvironmentVariables() = EnvironmentVariableConfigurationReader() :> IConfigurationReader - /// Create a configuration reader instance using the application's resident AppSettings configuration - static member FromAppSettings() = AppSettingsConfigurationReader() :> IConfigurationReader - /// Create a configuration reader instance using a local xml App.Config file - static member FromAppSettingsFile(path : string) = AppSettingsConfigurationFileReader.Create(path) :> IConfigurationReader - /// Create a configuration reader instance using the location of an assembly file - static member FromAppSettings(assembly : Assembly) = - let path = assembly.Location - if String.IsNullOrEmpty path then - sprintf "Assembly location for '%O' is null or empty." assembly.Location - |> invalidArg assembly.FullName - - AppSettingsConfigurationFileReader.Create(path + ".config") :> IConfigurationReader \ No newline at end of file diff --git a/tests/Argu.Tests/Argu.Tests.fsproj b/tests/Argu.Tests/Argu.Tests.fsproj index cf91aa9c..bfcffe8f 100644 --- a/tests/Argu.Tests/Argu.Tests.fsproj +++ b/tests/Argu.Tests/Argu.Tests.fsproj @@ -3,17 +3,18 @@ net6.0 - + - + + - + - - - - + + + +