I am trying to use dotCover in FAKE .I am getting an error i.e. DotCoverNUnit is not defined .I think this is the problem with the package .
Here is my Code for DotCover in FAKE :
let filters = ""
Target "TestCoverage" (fun _ ->
!! ("D:/Test/Project/Project1/UnitTests/UnitTest.dll")
|> DotCoverNUnit (fun p ->
{ p with
Output = testDir ## "NUnitDotCover.snapshot"
Filters = filters }) nunitOptions
)
Please tell me how to install DotCover in Fake or how to use this . This would be very helpful .
The Fake.DotCover module is not auto-opened, so its functions aren't available until you do open Fake.DotCover near the top of your script.
Unfortunately, the FAKE API documentation currently isn't very good at telling you which modules are auto-opened and which ones need open (modulename) in order to expose their functions.
Update: The way you should be calling DotCoverNUnit is as follows:
let filters = ""
Target "TestCoverage" (fun _ ->
!! ("D:/Test/Project/Project1/UnitTests/UnitTest.dll")
|> DotCoverNUnit
(fun p -> { p with Output = testDir ## "NUnitDotCover.snapshot"
Filters = filters })
(fun nunitOptions -> nunitOptions)
)
Or, if you want to change some of the NUnit options:
let filters = ""
Target "TestCoverage" (fun _ ->
!! ("D:/Test/Project/Project1/UnitTests/UnitTest.dll")
|> DotCoverNUnit
(fun dotCoverOptions ->
{ dotCoverOptions with Output = testDir ## "NUnitDotCover.snapshot"
Filters = filters })
(fun nunitOptions ->
{ nunitOptions with ExcludeCategory = "Manual,LongRunning"
DisableShadowCopy = true })
)
See http://fsharp.github.io/FAKE/apidocs/fake-nunitcommon-nunitparams.html for the complete list of what NUnit options are available from inside FAKE.
Related
try (box (Directory.GetDirectories(dir) ))
with | :? System.UnauthorizedAccessException -> ()
I'm trying to check if the directory is accessible so I won't get an "access denied" error, but it's not working, it's not skipping the loop in for
It's generally discouraged to use exceptions as part of your control flow. It's better to check for the appropriate access to the directory before trying to enumerate its contents. Try something like this:
open System
open System.IO
open System.Linq
open System.Security.AccessControl
open System.Security.Principal
let checkSecurity =
let account = sprintf #"%s\%s" Environment.UserDomainName Environment.UserName
let identity = WindowsIdentity.GetCurrent()
let principal = identity |> WindowsPrincipal
let isAdmin = identity.Owner = identity.User
fun (dir: DirectoryInfo) ->
try
let acl = dir.GetAccessControl(AccessControlSections.All)
let rules = acl.GetAccessRules(true, true, typeof<NTAccount>)
rules.OfType<FileSystemAccessRule>()
|> Seq.filter (fun rule -> rule.IdentityReference.Value.Equals(account, StringComparison.CurrentCultureIgnoreCase) ||
(if rule.IdentityReference.Value.Equals("BUILTIN\Administrators", StringComparison.CurrentCultureIgnoreCase)
then isAdmin && principal.IsInRole(rule.IdentityReference.Value)
else principal.IsInRole(rule.IdentityReference.Value)))
|> Seq.exists (fun rule -> (rule.FileSystemRights &&& FileSystemRights.Read = FileSystemRights.Read) && rule.AccessControlType <> AccessControlType.Deny)
with | _ ->
false
let rec getFiles (dir: DirectoryInfo) =
[ if checkSecurity dir
then for file in dir.GetFiles("*") do yield file
for subDir in dir.GetDirectories("*") do yield! getFiles subDir
]
let dir = DirectoryInfo(#"C:\Temp")
dir |> getFiles
You might have some other issues, if you have an exception the try-with block should be able to handle it, so either you're actually not getting an exception or have some other issues in the surrounding code. Why do you box?
The aversion to using exceptions as control flow makes some sense in .NET. in OCaml exceptions are used extensively for that purpose, but they are cheap. In .NET this is more expensive in performance terms. That said, sometimes you do want catch and handle an exception, so I don't think it's such a big issue. This for example works:
open System.IO
let okdir = #"c:\tmp"
let baddir = #"L:\Finance"
let checkDir dir =
try
Directory.GetDirectories(dir) |> ignore
printfn "%A" "Processed"
with
| :? System.UnauthorizedAccessException as ex -> failwith ex.Message
| :? System.IO.IOException as ex -> failwith ex.Message
// | :? System.Exception as ex -> failwith ex.Message
checkDir okdir
//"Processed"
//val it : unit = ()
checkDir baddir
//System.Exception: Access to the path 'L:\Finance' is denied.
I want to copy all files in a particular directory to destination directory.
My code is running perfectly but no files are being copied to the destination folder .
I have tried two approaches but no luck :(
Here is my code:
Approach 1:
#r #"packages\FAKE\tools\FakeLib.dll"
open Fake
let buildDir = "D:/MyDir/build/"
let testDir = "D:/MyDir/test/"
let sourceDir = "D:/Files"
// Targets
Target "Clean" (fun _ ->
CleanDirs [buildDir; testDir]
)
Target "BuildSetup" (fun _ ->
!!(sourceDir + "\**\*.txt")
|> Copy testDir)
"Clean"
==>"BuildSetup"
RunTargetOrDefault "BuildSetup"
Approach 2 :
#r #"packages\FAKE\tools\FakeLib.dll"
open Fake
let buildDir = "D:/MyDir/build/"
let testDir = "D:/MyDir/test/"
let sourceDir = "D:/Files"
// Targets
Target "Clean" (fun _ ->
CleanDirs [buildDir; testDir ;sourceDir]
)
Target "Default" (fun _ ->
trace "Hello World from FAKE"
)
let additionalFiles = ["D:\Files\new\*.*"]
Target "CopyFiles" (fun _ ->
CopyTo buildDir additionalFiles
)
Target "BuildSetup" (fun _ ->
!!("D:\Files\new\*.txt")
|> Copy buildDir)
"Clean"
//==> "Clean"
//==> "BuildStep"
==> "CopyFiles"
RunTargetOrDefault "BuildSetup"
this code is being run , but files are not copied to the destination folder .
please tell me root cause of the problem , I am new to fake .
The below is a working example:
#r "./packages/FAKE/tools/FakeLib.dll"
open Fake
let source = "C:/test/source"
let additionalFilesDir = "C:/test/additional"
let dest = "C:/test/dest/"
Target "Clean" (fun _ ->
CleanDirs [dest]
)
Target "Default" (fun _ ->
trace "Hello World from FAKE"
)
Target "CopyDirectory" (fun _ ->
CopyDir (directory dest) source allFiles
)
Target "CopyAdditionalFiles" (fun _ ->
!!(additionalFilesDir ## "**/*")
--(additionalFilesDir ## "**/*.txt") //exclude '.txt' files
|> Copy dest
//copy will NOT fail if directory not existing
if not <|directoryExists additionalFilesDir then
traceError ("additionalFilesDir doesn't exist:" + additionalFilesDir)
)
"Clean"
==> "CopyDirectory"
==> "CopyAdditionalFiles"
==> "Default"
RunTargetOrDefault "Default"
I have a FAKE build script that contains a DotCover coverage step using using the DotCoverNUnit3 extension:
let filters = ""
!! (buildDir ## "/*.UnitTests.dll")
|> DotCoverNUnit3 (fun p ->
{ p with
Output = artifactsDir ## "NUnitDotCover.snapshot"
Filters = filters }) nunitOptions
The snapshot generates correctly, but the coverage overview doesn't appear in the TeamCity build.
I then tried calling DotCoverReport after building the snapshot:
DotCoverReport (fun p ->
{ p with
Source = artifactsDir ## "NUnitDotCover.snapshot"
Output = artifactsDir ## "NUnitDotCover.xml"
ReportType = DotCoverReportType.Xml }) true
This generates the expected XML report, but again, the coverage overview doesn't appear in the build overview page.
As a side note - I'm not sure what the boolean parameter on the end of the DotCoverReport method is, can't find a reference to it on the FAKE docs. I tried switching the value, but it didn't make a difference.
Does anyone know how I can get TeamCity to pickup the DotCover report?
Found a solution.
After drilling down through many layers of TeamCity documentation, I found this page: https://confluence.jetbrains.com/display/TCD9/Manually+Configuring+Reporting+Coverage
Which describes using service messages to point TeamCity in the direction of the snapshot.
So, in the end I didn't need the DotCoverReport, just the snapshot:
For dotCover you should send paths to the snapshot file that is generated by the dotCover.exe cover command.
This is my resulting Target:
let artifactsDir = environVarOrDefault "ARTIFACT_DIR" (currentDirectory ## "artifacts")
let nunitOptions nUnit3Defaults =
{ NUnit3Defaults with
TimeOut = TimeSpan.MaxValue
WorkingDir = artifactsDir }
Target "TestCoverage" (fun _ ->
let filters = ""
!! (buildDir ## "/*.UnitTests.dll")
|> DotCoverNUnit3 (fun p ->
{ p with
Output = artifactsDir ## "NUnitDotCover.snapshot"
Filters = filters }) nunitOptions
tracefn "##teamcity[importData type='dotNetCoverage' tool='dotcover' path='%s']" (artifactsDir ## "NUnitDotCover.snapshot")
)
I'm messing with my new statically parameterized type provider that provides a type with statically parameterized static methods. I haven't found documentation about this not being allowed. I'm getting some strange type provider behavior:
This type-provider-consuming code runs correctly but the intellisense gives crappy info. Members just keep getting added but never removed. The OpDef method shouldn't be available without the type parameters but intellisense kinda shows that as an option but still gives an error about a missing invoker if I actually refer to it. The required arguments to the provided OpDef method are not shown - always shows OpDef() -> unit instead of OpDef(suffix : string * id : string) -> unit that I currently expect to see (from this draft of the type provider). But as I've given all the arguments it really needs then it stops complaining.
Am I doing something that isn't supported or correct? Or, doubtfully, is there a bug in the f# stuff (and can you isolate where the bug is apparent)?
Here is the full implementation which uses the starter-pack files.
namespace OfflineSql
open ProviderImplementation.ProvidedTypes
open Microsoft.FSharp.Core.CompilerServices
open System.Text.RegularExpressions
#nowarn "0025"
[<TypeProvider>]
type OfflineSqlProvider (config : TypeProviderConfig) as this =
inherit TypeProviderForNamespaces ()
let ns = "OfflineSql"
let asm = System.Reflection.Assembly.GetExecutingAssembly()
let buildDomainProvider nm schema invariants =
let parameterizedType = ProvidedTypeDefinition(asm, ns, nm, None)
let m = ProvidedMethod("OpDef", list.Empty, typeof<unit>, IsStaticMethod = true)
m.DefineStaticParameters(
[
ProvidedStaticParameter("script", typeof<string>)
],
fun nm [| :? string as operation |] ->
let results =
Regex.Matches(operation, "#([a-zA-Z_][a-zA-Z0-9_]*)") |> Seq.cast
|> Seq.map (fun (regmatch: Match) -> regmatch.Groups.[1].Captures.[0].ToString())
let ps = [ for a in results -> ProvidedParameter(a, typeof<string>) ] |> List.distinct
let opDef = ProvidedMethod(nm, ps, typeof<unit>, IsStaticMethod = true, InvokeCode = (fun _ -> <## () ##>))
opDef.AddXmlDoc("Constructs a guarded method for the operation's script")
parameterizedType.AddMember(opDef)
opDef)
let schemaProp =
ProvidedProperty("Schema", typeof<string>, IsStatic = true,
GetterCode = (fun _ -> <## schema ##>))
let invariantsProp =
ProvidedProperty("Invariants", typeof<string>, IsStatic = true,
GetterCode = (fun _ -> <## invariants ##>))
parameterizedType.AddMember(m)
parameterizedType.AddMember(schemaProp)
parameterizedType.AddMember(invariantsProp)
parameterizedType
do
let root = ProvidedTypeDefinition(asm, ns, "Domain", None)
root.DefineStaticParameters(
[
ProvidedStaticParameter("schema", typeof<string>)
ProvidedStaticParameter("invariants", typeof<string>, "")
],
fun nm [| :? string as schema ; :? string as invariants |] ->
buildDomainProvider nm schema invariants)
this.AddNamespace(ns, [ root ])
[<assembly:TypeProviderAssembly>]
do ()
This is directly related to known bugs with a fix:
https://github.com/Microsoft/visualfsharp/issues/642
https://github.com/Microsoft/visualfsharp/issues/640
https://github.com/Microsoft/visualfsharp/pull/705
Thanks to #gauthier on functionalprogramming.slack.com/fsharp for this find.
First let me apologize for the scale of this problem but I'm really trying to think functionally and this is one of the more challenging problems I have had to work with.
I wanted to get some suggestions on how I might handle a problem I have in a functional manner, particularly in F#. I am writing a program to go through a list of directories and using a list of regex patterns to filter the list of files retrieved from the directories and using a second list of regex patterns to find matches in the text of the retreived files. I want this thing to return the filename, line index, column index, pattern and matched value for each piece of text that matches a given regex pattern. Also, exceptions need to be recorded and there are 3 possible exceptions scenarios: can't open the directory, can't open the file, reading content from the file failed. The final requirement of this is the the volume of files "scanned" for matches could be very large so this whole thing needs to be lazy. I'm not too worried about a "pure" functional solution as much as I'm interested in a "good" solution that reads well and performs well. One final challenge is to make it interop with C# because I would like to use the winform tools to attach this algorithm to a ui. Here is my first attempt and hopefully this will clarify the problem:
open System.Text.RegularExpressions
open System.IO
type Reader<'t, 'a> = 't -> 'a //=M['a], result varies
let returnM x _ = x
let map f m = fun t -> t |> m |> f
let apply f m = fun t -> t |> m |> (t |> f)
let bind f m = fun t -> t |> (t |> m |> f)
let Scanner dirs =
returnM dirs
|> apply (fun dirExHandler ->
Seq.collect (fun directory ->
try
Directory.GetFiles(directory, "*", SearchOption.AllDirectories)
with | e ->
dirExHandler e directory
Array.empty))
|> map (fun filenames ->
returnM filenames
|> apply (fun (filenamepatterns, lineExHandler, fileExHandler) ->
Seq.filter (fun filename ->
filenamepatterns |> Seq.exists (fun pattern ->
let regex = new Regex(pattern)
regex.IsMatch(filename)))
>> Seq.map (fun filename ->
let fileinfo = new FileInfo(filename)
try
use reader = fileinfo.OpenText()
Seq.unfold (fun ((reader : StreamReader), index) ->
if not reader.EndOfStream then
try
let line = reader.ReadLine()
Some((line, index), (reader, index + 1))
with | e ->
lineExHandler e filename index
None
else
None) (reader, 0)
|> (fun lines -> (filename, lines))
with | e ->
fileExHandler e filename
(filename, Seq.empty))
>> (fun files ->
returnM files
|> apply (fun contentpatterns ->
Seq.collect (fun file ->
let filename, lines = file
lines |>
Seq.collect (fun line ->
let content, index = line
contentpatterns
|> Seq.collect (fun pattern ->
let regex = new Regex(pattern)
regex.Matches(content)
|> (Seq.cast<Match>
>> Seq.map (fun contentmatch ->
(filename,
index,
contentmatch.Index,
pattern,
contentmatch.Value))))))))))
Thanks for any input.
Updated -- here is any updated solution based on feedback I received:
open System.Text.RegularExpressions
open System.IO
type ScannerConfiguration = {
FileNamePatterns : seq<string>
ContentPatterns : seq<string>
FileExceptionHandler : exn -> string -> unit
LineExceptionHandler : exn -> string -> int -> unit
DirectoryExceptionHandler : exn -> string -> unit }
let scanner specifiedDirectories (configuration : ScannerConfiguration) = seq {
let ToCachedRegexList = Seq.map (fun pattern -> new Regex(pattern)) >> Seq.cache
let contentRegexes = configuration.ContentPatterns |> ToCachedRegexList
let filenameRegexes = configuration.FileNamePatterns |> ToCachedRegexList
let getLines exHandler reader =
Seq.unfold (fun ((reader : StreamReader), index) ->
if not reader.EndOfStream then
try
let line = reader.ReadLine()
Some((line, index), (reader, index + 1))
with | e -> exHandler e index; None
else
None) (reader, 0)
for specifiedDirectory in specifiedDirectories do
let files =
try Directory.GetFiles(specifiedDirectory, "*", SearchOption.AllDirectories)
with e -> configuration.DirectoryExceptionHandler e specifiedDirectory; [||]
for file in files do
if filenameRegexes |> Seq.exists (fun (regex : Regex) -> regex.IsMatch(file)) then
let lines =
let fileinfo = new FileInfo(file)
try
use reader = fileinfo.OpenText()
reader |> getLines (fun e index -> configuration.LineExceptionHandler e file index)
with | e -> configuration.FileExceptionHandler e file; Seq.empty
for line in lines do
let content, index = line
for contentregex in contentRegexes do
for mmatch in content |> contentregex.Matches do
yield (file, index, mmatch.Index, contentregex.ToString(), mmatch.Value) }
Again, any input is welcome.
I think that the best approach is to start with the simplest solution and then extend it. Your current approach seems to be quite hard to read to me for two reasons:
The code uses a lot of combinators and function compositions in patterns that are not too common in F#. Some of the processing can be more easily written using sequence expressions.
The code is all written as a single function, but it is fairly complex and would be more readable if it was separated into multiple functions.
I would probably start by splitting the code in a function that tests a single file (say fileMatches) and a function that walks over the files and calls fileMatches. The main iteration can be quite nicely written using F# sequence expressions:
// Checks whether a file name matches a filename pattern
// and a content matches a content pattern.
let fileMatches fileNamePatterns contentPatterns
(fileExHandler, lineExHandler) file =
// TODO: This can be imlemented using
// File.ReadLines which returns a sequence.
// Iterates over all the files and calls 'fileMatches'.
let scanner specifiedDirectories fileNamePatterns contentPatterns
(dirExHandler, fileExHandler, lineExHandler) = seq {
// Iterate over all the specified directories.
for specifiedDir in specifiedDirectories do
// Find all files in the directories (and handle exceptions).
let files =
try Directory.GetFiles(specifiedDir, "*", SearchOption.AllDirectories)
with e -> dirExHandler e specifiedDir; [||]
// Iterate over all files and report those that match.
for file in files do
if fileMatches fileNamePatterns contentPatterns
(fileExHandler, lineExHandler) file then
// Matches! Return this file as part of the result.
yield file }
The function is still quite complicated, because you need to pass a lot of parameters around. Wrapping the parameters in a simple type or a record could be a good idea:
type ScannerArguments =
{ FileNamePatterns:string
ContentPatterns:string
FileExceptionHandler:exn -> string -> unit
LineExceptionHandler:exn -> string -> unit
DirectoryExceptionHandler:exn -> string -> unit }
Then you can define both fileMatches and scanner as functions that take just two parameters, which will make your code a lot more readable. Something like:
// Iterates over all the files and calls 'fileMatches'.
let scanner specifiedDirectories (args:ScannerArguments) = seq {
for specifiedDir in specifiedDirectories do
let files =
try Directory.GetFiles(specifiedDir, "*", SearchOption.AllDirectories)
with e -> args.DirectoryExceptionHandler e specifiedDir; [||]
for file in files do
// No need to propagate all arguments explicitly to other functions.
if fileMatches args file then yield file }