As I will be using Fake for handling task automation, and Tomas's Formatting library as well, I wanted to add a helper to integrate both.
That lead me to look at how dependencies are managed on the task level.
let Install setParams setup =
if not (execProcess3 (fun info -> info.FileName <- parameters.ToolPath // "msiexec " by default
info.WorkingDirectory <- parameters.WorkingDir
info.Arguments <- sprintf "/qb /l* %s /i %s" parameters.LogFile setup) parameters.TimeOut) && parameters.ThrowIfSetupFails
That is, we just assume "msiexec" command to be there, or wherever the caller decided it should be.
It is entirely up to the outside environment's responsibility to resolve the dependencies beforehand and to supply them to the Fake layer independently.
Now, for the specific part of delivering a versioned binary, nuget is here to help.
But the beauty of nuget is that though its packages.config file allows others (fsproj) to make assumptions on what is here or not.
And those project reference exactly this reference.
In Fake, I can write a helper, which will conform to Formatting1.x version, declaring and fulfilling my dependency by other means.
Then someone else tries to use this helper with another version of the nugget, and it will fail.
It could be because of the signature, or because the gem moved its binary and I obviously hard coded both.
Fake Helper does not use versioning for its dependencies, and relegate the problem outside.
What would be the solution ?
- Pushing the binaries inside Fake, that is remove any reference to the outside world. This is good at a small scale, like "./tools/ILMerge/ilmerge.exe" but unmanageable more widely
- Having a mapping file that would specify among different Helper which target different versions of the same external program, the one to use
A type provider would then populate a unversioned namespace with the functions and type provided. This would allow to let the type information flow to build.fsx while keeping an extensibility point which only does namespace redirection between. (Fake.DocuHelper and module Fake.DocuHelper1.2.3 for instance)
- For nugets that would want to be fake-compatible, having a generic FakeHelperAttribute(defaultarg) on top of the functions that it wants to expose.
Then a type provider would inspect the chosen nugets for the specific project and make them accessible
let nugetHelpers = FakeNugetHelper<"package.config", ".packages">
and expose them for consumption in the script build.fsx
If we look at how this is solved in homebrew, we see that they integrated both aspects of nugets (dependency management) and install steps, which makes it manageable to have no type check on the argument I guess. And it works amazingly well.
It is very easy to contribute new formulas to their system, and it would be massively good to have this scaling capacity