Scripting in F# Using Fake and Paket
Scripting in F# is usually done using .fsx files and F# Interactive (Fsi). For scripts that will be reused, Paket and Fake bring several features to handle different uses cases. Fake can be used to structure complex scripts, while Paket brings dependency management.
While Fake is, at its core, a build tool, its target system can also be used to structure scripts. Targets can be defined in relation to each other, which is common in scripts. Using Fake also allows the use of any .Net library. The following snippet shows the definition of two targets to run FluentMigrator migrations:
open System.Management.Automation Target "BuildMigrations" (fun _ -> !! "src/app/**/migrations.csproj" |> MSBuildRelease buildDir "Build" ) Target "RunMigrations" (fun _ -> MigrateToLatest connectionString [assembly] options ) // Dependencies "BuildMigrations" ==> "RunMigrations"
A desirable property of scripting languages is the ability to run small snippets code without prior compilation. F# can meet that requirement through F# Interactive (Fsi), although this mean installing Fsi on all machines where the script will run. Fake, on the other hand, can run scripts without prior compilation. It also doesn’t need the F# compiler on the machine where it runs. This capability comes from the F# Compiler Services project, embedding the compiler directly into Fake.
It is also possible to run Powershell scripts from Fake, allowing to mix and match F# and Powershell when needed.
open System.Management.Automation Target "Powershell" (fun _ -> PowerShell.Create() .AddScript("& 'configure-server.ps1'") .AddParameter("Verbose", "") .Invoke())
Some scripts, especially when dealing with external services, require additional libraries. Albeit it is less common for scripting, dependencies can also be managed with a package manager. Using Paket, it is possible to reference individual files, another common case when scripting.
// Reference a nuget package nuget FSharp.Management // Reference a single file from GitHub github myRepo/aProject dependency.dll
Paket also provides the ability to group dependencies so that it doesn’t need to fetch all packages when only a subset is needed. This is well-suited for scripts, where several scripts may use the same dependencies file.
// Shared dependencies nuget Newtonsoft.Json nuget FSharp.Core group Web nuget Fake.IIS nuget Suave group Database nuget FluentMigrator nuget SQLProvider
Packages in F# scripts are referenced directly by path to the dynamic library. The references must be added and maintained manually, which can be time consuming with bigger scripts. Paket has the ability to generate a file including all the dependencies, removing the step of keeping in sync #r directives and referenced packages.
This post is part of the F# advent calendar, an initiative of the F# community.