Skip to content

Commit

Permalink
Merge pull request #116 from rojepp/fix_filewatcher
Browse files Browse the repository at this point in the history
Make FileSystemWatcher more reliable
  • Loading branch information
dmitry-a-morozov committed Feb 16, 2015
2 parents ae07002 + abbb977 commit f76379c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/SqlClient.Samples/WebApi.Controllers/DataAccess.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ open FSharp.Data
[<Literal>]
let AdventureWorks2012 = "name=AdventureWorks2012"

type QueryProducts = SqlCommandProvider<"T-SQL\Products.sql", AdventureWorks2012, DataDirectory = "App_Data">
type QueryProducts = SqlCommandProvider<"T-SQL/Products.sql", AdventureWorks2012, DataDirectory = "App_Data">

type AdventureWorks = SqlProgrammabilityProvider<AdventureWorks2012, DataDirectory = "App_Data">

9 changes: 9 additions & 0 deletions src/SqlClient.Tests/ConfigurationTest.fs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ let RuntimeConfig () =
Configuration.GetConnectionStringAtRunTime name
|> should equal ConfigurationManager.ConnectionStrings.[name].ConnectionString

[<Fact>]
let CheckValidFileName() =
let expected = Some "c:\\mysqlfiles\\test.sql"
Configuration.GetValidFileName("test.sql", "c:\\mysqlfiles") |> should equal expected
Configuration.GetValidFileName("../test.sql", "c:\\mysqlfiles\\subfolder") |> should equal expected
Configuration.GetValidFileName("c:\\mysqlfiles/test.sql", "d:\\otherdrive") |> should equal expected
Configuration.GetValidFileName("../mysqlfiles/test.sql", "c:\\otherfolder") |> should equal expected
Configuration.GetValidFileName("a/b/c/../../../test.sql", "c:\\mysqlfiles") |> should equal expected

type Get42RelativePath = SqlCommandProvider<"sampleCommand.sql", "name=AdventureWorks2012", ResolutionFolder="MySqlFolder">

type Get42 = SqlCommandProvider<"SELECT 42", "name=AdventureWorks2012", ConfigFile = "appWithInclude.config">
27 changes: 17 additions & 10 deletions src/SqlClient/Configuration.fs
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,34 @@ open System.Threading.Tasks
open System.Collections.Generic

type Configuration() =
static let isInvalidPathChars = HashSet(Path.GetInvalidPathChars())
static let invalidPathChars = HashSet(Path.GetInvalidPathChars())
static let invalidFileChars = HashSet(Path.GetInvalidFileNameChars())

static member GetValidFileName (file:string, resolutionFolder:string) =
if (file.Contains "\n") || (resolutionFolder.Contains "\n") then None else
let f = Path.Combine(resolutionFolder, file)
if invalidPathChars.Overlaps (Path.GetDirectoryName f) ||
invalidFileChars.Overlaps (Path.GetFileName f) then None
else
// Canonicalizing the path may throw on bad input, the check above does not cover every error.
try Some (Path.GetFullPath f) with | _ -> None

static member ParseTextAtDesignTime(commandTextOrPath : string, resolutionFolder, invalidateCallback) =
if isInvalidPathChars.Overlaps( commandTextOrPath)
then commandTextOrPath, None
else
let path = Path.Combine(resolutionFolder, commandTextOrPath)
if File.Exists(path) |> not
then commandTextOrPath, None
else
if Path.GetExtension(commandTextOrPath) <> ".sql" then failwith "Only files with .sql extension are supported"
let watcher = new FileSystemWatcher(Filter = commandTextOrPath, Path = resolutionFolder)
match Configuration.GetValidFileName (commandTextOrPath, resolutionFolder) with
| Some path when File.Exists path ->
if Path.GetExtension(path) <> ".sql" then failwith "Only files with .sql extension are supported"
let watcher = new FileSystemWatcher(Filter = Path.GetFileName path, Path = Path.GetDirectoryName path)
watcher.Changed.Add(fun _ -> invalidateCallback())
watcher.Renamed.Add(fun _ -> invalidateCallback())
watcher.Deleted.Add(fun _ -> invalidateCallback())
watcher.EnableRaisingEvents <- true
let task = Task.Factory.StartNew(fun () ->
use stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
use reader = new StreamReader(stream)
reader.ReadToEnd())
if not (task.Wait(TimeSpan.FromSeconds(1.))) then failwithf "Couldn't read command from file %s" path
task.Result, Some watcher
| _ -> commandTextOrPath, None

static member ParseConnectionStringName(s: string) =
match s.Trim().Split([|'='|], 2, StringSplitOptions.RemoveEmptyEntries) with
Expand Down

0 comments on commit f76379c

Please sign in to comment.