Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/FSharp.Configuration/AppSettingsProvider.fs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
module FSharp.Configuration.AppSettingsTypeProvider

open FSharp.Configuration.Helper
open Microsoft.FSharp.Core.CompilerServices
open Samples.FSharp.ProvidedTypes
open System
open System.Configuration
open System.IO
open System.Reflection
open System.Collections.Generic
open System.Globalization

Expand Down Expand Up @@ -63,7 +60,6 @@ let internal typedAppSettings (context: Context) =
typeDef.AddMember prop
context.WatchFile filePath
typeDef
with
| exn -> typeDef
with _ -> typeDef
| x -> failwithf "unexpected parameter values %A" x))
appSettings
5 changes: 1 addition & 4 deletions src/FSharp.Configuration/ConfigTypeProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ open FSharp.Configuration.Helper
open Microsoft.FSharp.Core.CompilerServices
open Samples.FSharp.ProvidedTypes
open System
open System.Configuration
open System.IO
open System.Reflection

[<TypeProvider>]
type public FSharpConfigurationProvider(cfg: TypeProviderConfig) as this =
Expand All @@ -18,7 +15,7 @@ type public FSharpConfigurationProvider(cfg: TypeProviderConfig) as this =
ResXProvider.typedResources context
YamlConfigTypeProvider.typedYamlConfig context ])
interface IDisposable with
member x.Dispose() = dispose context
member __.Dispose() = dispose context

[<TypeProviderAssembly>]
do ()
4 changes: 1 addition & 3 deletions src/FSharp.Configuration/ResXProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
open System
open System.IO
open System.Reflection
open Microsoft.FSharp.Core.CompilerServices
open Samples.FSharp.ProvidedTypes
open FSharp.Configuration.Helper
open System.Resources
open System.ComponentModel.Design
open System.Collections
open Microsoft.FSharp.Quotations

let readValue (filePath: FilePath, name) =
use reader = new ResXResourceReader(filePath)
Expand All @@ -30,7 +28,7 @@ let internal toProperties (resXFilePath:string) =
let name = node.Name
let typ = node.GetValueTypeName(Unchecked.defaultof<ITypeResolutionService>) |> System.Type.GetType
let comment = node.Comment
let getter args = <@@ readValue(resXFilePath, name) @@>
let getter _args = <@@ readValue(resXFilePath, name) @@>
let resource = ProvidedProperty(name, typ, IsStatic=true, GetterCode=getter)
if not(String.IsNullOrEmpty(comment)) then resource.AddXmlDoc(node.Comment)
resource :> MemberInfo ]
Expand Down
102 changes: 87 additions & 15 deletions src/FSharp.Configuration/TypeProviders.Helper.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open System
open System.IO
open Samples.FSharp.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
open Microsoft.FSharp.Core.Printf

type FilePath = string

Expand All @@ -18,6 +19,7 @@ let inline satisfies predicate (charOption:option<char>) =
| _ -> None

let dispose (x: IDisposable) = if x = null then () else x.Dispose()
let inline debug msg = Printf.kprintf Diagnostics.Debug.WriteLine msg

let (|EOF|_|) = function
| Some _ -> None
Expand All @@ -27,6 +29,85 @@ let (|LetterDigit|_|) = satisfies Char.IsLetterOrDigit
let (|Upper|_|) = satisfies Char.IsUpper
let (|Lower|_|) = satisfies Char.IsLower

[<RequireQualifiedAccess>]
module Option =
let inline ofNull value =
if obj.ReferenceEquals(value, null) then None else Some value

/// Gets the option if Some x, otherwise the supplied default value.
let inline orElse v =
function
| Some x -> Some x
| None -> v

/// Gets the value associated with the option or the supplied default value.
let inline getOrElse v =
function
| Some x -> x
| None -> v

/// Maybe computation expression builder, copied from ExtCore library
/// https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/Control.fs
[<Sealed>]
type MaybeBuilder () =
// 'T -> M<'T>
member inline __.Return value: 'T option =
Some value

// M<'T> -> M<'T>
member inline __.ReturnFrom value: 'T option =
value

// unit -> M<'T>
member inline __.Zero (): unit option =
Some () // TODO: Should this be None?

// (unit -> M<'T>) -> M<'T>
member __.Delay (f: unit -> 'T option): 'T option =
f ()

// M<'T> -> M<'T> -> M<'T>
// or
// M<unit> -> M<'T> -> M<'T>
member inline __.Combine (r1, r2: 'T option): 'T option =
match r1 with
| None ->
None
| Some () ->
r2

// M<'T> * ('T -> M<'U>) -> M<'U>
member inline __.Bind (value, f: 'T -> 'U option): 'U option =
Option.bind f value

// 'T * ('T -> M<'U>) -> M<'U> when 'U :> IDisposable
member __.Using (resource: ('T :> System.IDisposable), body: _ -> _ option): _ option =
try body resource
finally
if not <| obj.ReferenceEquals (null, box resource) then
resource.Dispose ()

// (unit -> bool) * M<'T> -> M<'T>
member x.While (guard, body: _ option): _ option =
if guard () then
// OPTIMIZE: This could be simplified so we don't need to make calls to Bind and While.
x.Bind (body, (fun () -> x.While (guard, body)))
else
x.Zero ()

// seq<'T> * ('T -> M<'U>) -> M<'U>
// or
// seq<'T> * ('T -> M<'U>) -> seq<M<'U>>
member x.For (sequence: seq<_>, body: 'T -> unit option): _ option =
// OPTIMIZE: This could be simplified so we don't need to make calls to Using, While, Delay.
x.Using (sequence.GetEnumerator (), fun enum ->
x.While (
enum.MoveNext,
x.Delay (fun () ->
body enum.Current)))

let maybe = MaybeBuilder()

[<RequireQualifiedAccess>]
module ValueParser =
open System.Globalization
Expand Down Expand Up @@ -113,18 +194,9 @@ let findConfigFile resolutionFolder configFileName =
let erasedType<'T> assemblyName rootNamespace typeName =
ProvidedTypeDefinition(assemblyName, rootNamespace, typeName, Some(typeof<'T>))

let generalTypeSet = System.Collections.Generic.HashSet()

let runtimeType<'T> typeName = ProvidedTypeDefinition(niceName generalTypeSet typeName, Some typeof<'T>)

let seqType ty = typedefof<seq<_>>.MakeGenericType[| ty |]
let listType ty = typedefof<list<_>>.MakeGenericType[| ty |]
let optionType ty = typedefof<option<_>>.MakeGenericType[| ty |]

// Get the assembly and namespace used to house the provided types
let thisAssembly = System.Reflection.Assembly.GetExecutingAssembly()
let rootNamespace = "FSharp.Configuration"
let missingValue = "@@@missingValue###"

module File =
let tryOpenFile filePath =
Expand All @@ -146,12 +218,12 @@ module File =
| 0, x -> return x
| _, "" ->
printfn "Attempt %d of %d: %s is empty. Sleep for 1 sec, then retry..." attempt maxAttempts filePath
return! sleepAndRun (attempt - 1)
return! sleepAndRun attempt
| _, content -> return content
finally file.Dispose()
| None ->
printfn "Attempt %d of %d: cannot read %s. Sleep for 1 sec, then retry..." attempt maxAttempts filePath
return! sleepAndRun (attempt - 1) }
return! sleepAndRun attempt }
loop maxAttempts |> Async.RunSynchronously

type private State =
Expand All @@ -162,7 +234,7 @@ module File =
let getLastWrite() = File.GetLastWriteTime filePath
let state = ref { LastFileWriteTime = getLastWrite(); Updated = DateTime.Now }

let changed (args: FileSystemEventArgs) =
let changed (_: FileSystemEventArgs) =
let curr = getLastWrite()
// log (sprintf "%A. Last = %A, Curr = %A" args.ChangeType !lastWrite curr)
if curr <> (!state).LastFileWriteTime && DateTime.Now - (!state).Updated > TimeSpan.FromMilliseconds 500. then
Expand Down Expand Up @@ -220,8 +292,8 @@ type Context (provider: TypeProviderForNamespaces, cfg: TypeProviderConfig) =
loop Map.empty
)

member x.ResolutionFolder = cfg.ResolutionFolder
member x.WatchFile (file: FilePath) = agent.Post (Watch file)
member __.ResolutionFolder = cfg.ResolutionFolder
member __.WatchFile (file: FilePath) = agent.Post (Watch file)

interface IDisposable with
member x.Dispose() = agent.Post Cancel
member __.Dispose() = agent.Post Cancel
Loading