Looking at the WixHelper for F# documentation it looks like I can pass in a -filter parameter. I am still learning F# and I can't figure out how this method is supposed to work.
https://github.com/fsharp/FAKE/blob/master/src/app/FakeLib/WiXHelper.fs#L60-60
METHOD
wixDir fileFilter asSubDir directoryInfo
I am trying to adapt this call to filter out *.exe (I do not want to include them).
wixDir (fun file -> true) true (DirectoryInfo (buildDir ## "/SetupFiles"))
You just need to change (fun file -> true) to only return true when the file doesn't end with ".exe" I assume file is a FileInfo, so you would check if the file extension is "exe". I haven't tested this, but it should be something like this:
(fun file -> not (file.Extension = ".exe"))
Related
I am struggling with how to set different cache response headers based on whether the result is an Ok or an Error. My code is something like the following (but with other types in the result):
let resultToJson (result:Result<'a,string>) : HttpHandler =
match result with
| Ok o -> Successful.ok (json o)
| Error s -> ServerErrors.internalError (text s)
I can add the headers by doing something like the following:
let resultToJson (result:Result<'a,string>) : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
let response =
let headers = ctx.Response.Headers
match result with
| Ok o ->
headers.Add("Cache-Control", new StringValues("public, max-age=10, stale-while-revalidate=2"))
headers.Add("Vary", new StringValues("Origin"))
Successful.ok (json o)
| Error s ->
headers.Add("Cache-Control", new StringValues("no-cache"))
ServerErrors.internalError (text s)
response next ctx
But this does not feel right. I would like to use the standard HttpHandlers from the ResponseCaching module to set the right cache headers:
publicResponseCaching 10 (Some "Origin") // For Ok: Add 10 sec public cache, Vary by Origin
noResponseCaching // For Error: no caching
How do I achieve this?
The response cache handler is supposed to be piped into an normal pipeline. Your choice between Ok and Error is a choose function, so you can use a choose that takes a list of handlers that can be attempted. To reject a path, just return a task { return None }, to move forward, it's next ctx.
If you want to keep all the logic in one controller, like you have now, just keep your match and pipe your json/text response into one of the caching handlers.
let fn = json o >=> publicResponseCaching 30 None) in fn next ctx
if it's nested inside a hander, instead of in a pipeline, you have to apply the next & ctx
I found the solution to my problem.
Yes, I can chain the HttpHandlers like Gerard and Honza Brestan mentioned, using the fish operator (>=>). The reason I could not make that work in the first place was that I also had created a fish operator for the Result type in an opened module. Basically I had created proper fish soup
As soon as I refactored my code so that the module containing the Result fish operator was not open in this scope, everything worked fine as expected.
Another point to remember is that response caching needs to be called before the finalizing HttpHandler, otherwise it will not be called:
// Simplified code
let resultToJson =
function
| Ok o -> publicResponseCaching 10 (Some "Origin") >=> Successful.ok(json o)
| Error e -> noResponseCaching >=> ServerErrors.internalError(text e)
EDITED to show the ignore return as pointed out by Fyodor and the resulting error
I have a .fsx file with several targets that work as expected, but I can't get a target for OpenCover to work. This is what I have for the Target code:
Target "Coverage" (fun _ ->
OpenCover
(fun p -> { p with ExePath = "./packages/OpenCover.4.6.519/tools/OpenCover.Console.exe"
TestRunnerExePath = "./packages/Machine.Specifications.Runner.Console.0.10.0-Unstable0005/tools/mspec-clr4.exe"
Output = reportDir + "MspecOutput.xml"
Register = "-register:user"
}
)
testDir ## "FakeTest2UnitTesting.dll" + "--xml " + reportDir + "MspecOutput.xml" |> ignore
)
But I now get the following build error:
build.fsx(45,3): error FS0039: The value or constructor 'OpenCover' is not defined. Maybe you want one of the following:
OpenCoverHelper
NCover
I don't know what I am doing wrong. Can someone show me how to use the OpenCoverHelper from the FAKE API?
Thanks
After a lot of playing around an googling, I finally came up with the solution. The basic problem was that I didn't open the OpenCoverHelper. I made the assumption that it was included in FAKE as it is in the Api and there was no documentation saying anything else. So, here is the code I use:
// include Fake lib
#r #"packages/FAKE.4.61.2/tools/FakeLib.dll"
open Fake
open Fake.OpenCoverHelper
Target "Coverage" (fun _ ->
OpenCover (fun p -> { p with
ExePath = "./packages/OpenCover.4.6.519/tools/OpenCover.Console.exe"
TestRunnerExePath = "./packages/Machine.Specifications.Runner.Console.0.10.0-Unstable0005/tools/mspec-clr4.exe"
Output = "./report/MspecOutput.xml"
Register = RegisterUser
})
"./test/FakeTest2UnitTesting.dll + --xml ./report/MspecOutput.xml"
)
Hopefully this will help someone in the future.
I am working on an Elixir/Phoenix app that is intended to create a user in my UserController controller. There is a /lib/helpers/user_helpers directory with a number of modules (each in a separate file). These modules all have a common namespace UserHelpers.ModuleName. In each of these modules I have a function called apply which I want to apply to the user data. For example if I have the following file structure:
-lib
-helpers
-user_helpers
-module1
-module2
-...
-moduleN-1
-moduleN
where each of module1 and module2 contains a function apply(user_info) which returns user_info. In my UserController I have the function create(conn, params) in which I want to run the following:
user_data
|> UserHelpers.Module1.create
|> UserHelpers.Module2.create
|> ...
|> UserHelpers.ModuleN-1.create
|> UserHelpers.ModuleN.create
But I'm unsure how to dynamically load all of the modules in the UserHelpers folders to do the above. Any suggestions?
Assuming, that your application is called :my_app and helpers have the .ex extension and/or explicitly compiled into your application:
with {:ok, list} <- :application.get_key(:my_app, :modules) do
list
|> Enum.filter(& &1 |> Module.split |> Enum.take(1) == ~w|UserHelpers|)
|> Enum.reduce(user_data, fn m, acc -> apply(m, :create, acc) end)
end
:application.get_key(:my_app, :modules) returns the list of modules, known to that application. The second line filters out those unneeded, and the latter one applies their :create functions to user_data subsequently.
You probably want to embed Enum.sort just before the last line to sort the modules to apply in the appropriate order.
How can I access yaws file without including it's extension? Say,
www.domain.com/listen.yaws => www.domain.com/listen
I could not find any specific documentation for this from yaws documentation/appmod.
I think the question is ultimately clarified!
You can find one example of how to accomplish this in the "Arg Rewrite" section (7.1.2) of the Yaws PDF documentation. Set the variable arg_rewrite_mod in your server configuration to the name of an Erlang module supporting rewriting:
arg_rewrite_mod = my_rewriter
To support rewriting, the my_rewriter module must define and export an arg_rewrite/1 function, taking an #arg{} record as its argument:
-module(my_rewriter).
-export([arg_rewrite/1]).
-include_lib("yaws/include/yaws_api.hrl").
rewrite_pages() ->
["/listen"].
arg_rewrite(Arg) ->
Req = Arg#arg.req,
{abs_path, Path} = Req#http_request.path,
case lists:member(Path, rewrite_pages()) of
true ->
Arg#arg{req = Req#http_request{path = {abs_path, Path++".yaws"}}};
false ->
Arg
end.
The code includes yaws_api.hrl to pick up the #arg{} record definition.
The rewrite_pages/0 function returns a list of pages that must be rewritten to include ".yaws" suffixes; in this example, it's just the /listen page you mention in your question. If in arg_rewrite/1 we find the requested page in that list, we append ".yaws" to the page name and include it in a new #arg{} we return to Yaws, which then continues dispatching the request based on the new #arg{}.
I found this function Exec here http://fsharp.github.io/FAKE/apidocs/fake-processhelper-shell.html.
Target "UpdateTools" (fun _ ->
Exec "cmd"
)
But I keep getting this error, when I try to run it: "The value or constructor 'Exec' is not defined".
I'm new to FAKE and have not used F#, so forgive me if this should be obvious.
Can someone tell me why this api is not accessible like that?
The documentation is documenting class Shell. That means, you need to call it like:
Target "UpdateTools" (fun _ ->
ignore(Shell.Exec "cmd")
)
or, if you need to work with the error code further:
Target "UpdateTools" (fun _ ->
let errorCode = Shell.Exec "cmd"
//do something with the error code
()
)
Hope it is a bit clearer now.