A couple of years ago I blogged Dispelling the magic!, a post explaining the internals of the Cake build orchestration tool, with that post as a proof of concept I created Cake.Bridge assembly which provided an easy way from any .NET language get access to Cake abstractions and addins from a single instance static class.
Cake has some real nice testable abstractions around working with the filesystem, processes, tools, etc. and for a .NET project, we had just that need. But a static instance isn't very testable, and for most of our .NET projects (console apps, APIs, Azure Functions, WPF, etc.) we now use dependency injection using Microsoft.Extensions.DependencyInjection.
So with that in mind, I created an extension method to IServiceCollection that easily provided me a way to get a IFileSystem injected and utilizing the FakeFileSystem provided by Cake.Testing for testing. That grew into supporting most core Cake types including the more complex ICakeContext and IScriptHost.
If we got a need, chances are someone else has it too, so I've open-sourced the code and made it available as a NuGet package. It's early bits tailored for a specific need, so you should expect some rough edges, but sharing is caring.
The assembly is published at NuGet.org/packages/Cake.Bridge.DependencyInjection.
dotnet add package Cake.Bridge.DependencyInjection
<PackageReference Include="Cake.Bridge.DependencyInjection" Version="0.1.0" />
using Cake.Bridge.DependencyInjection; ... serviceCollection .AddCakeCore();
using Cake.Core; ... var cakeContext = serviceProvider.GetRequiredService<ICakeContext>();
Once registered you can now via dependency injection access the majority Cake.Core interfaces with ease, i.e:
- ICakeContext - Gives access to Cake built-in and addin aliases, and most Cake abstractions.
- IScriptHost - Gives access to script/task runner.
- ICakeLog - Cake logging implementation.
- IFileSystem - Cake file system abstraction.
using Cake.Bridge.DependencyInjection; using Cake.Core; using Cake.Core.Diagnostics; using Microsoft.Extensions.DependencyInjection; var serviceCollection = new ServiceCollection() .AddCakeCore(); var serviceProvider = serviceCollection.BuildServiceProvider(); var cakeContext = serviceProvider.GetRequiredService<ICakeContext>(); cakeContext.Log.Write( Verbosity.Normal, LogLevel.Information, "Hello World!");
Example IScriptHost and Cake.Common
Cake.Common contains Cake aliases normally ships together with the Cake script runner, when using Cake Bridge you'll need to add it to you project (same for any Cake addin).
dotnet add package Cake.Common --version 1.0.0-rc0002
<PackageReference Include="Cake.Common" Version="1.0.0-rc0002" />
then add the appropriate using statements and you can achieve something very similar to a Cake "script"
using Cake.Bridge.DependencyInjection; using Cake.Core; using Cake.Common.Diagnostics; using Cake.Core.Scripting; using Microsoft.Extensions.DependencyInjection; var serviceCollection = new ServiceCollection() .AddCakeCore(); var serviceProvider = serviceCollection.BuildServiceProvider(); var scriptHost = serviceProvider.GetRequiredService<IScriptHost>(); scriptHost.Task("Hello") .Does(ctx => ctx.Information("Hello")); scriptHost.Task("World") .IsDependentOn("Hello") .Does(ctx => ctx.Information("World")); await scriptHost.RunTargetAsync("World");
======================================== Hello ======================================== Hello ======================================== World ======================================== World Task Duration -------------------------------------------------- Hello 00:00:00.0226275 World 00:00:00.0002682 -------------------------------------------------- Total: 00:00:00.0228957
Complete example project
A full example console application using Spectre.Console demonstrating usage of both ICakeContext and IScriptHost can be found in project's GitHub repository at src/Cake.Bridge.DependencyInjection.Example.
- GitHub - github.com/devlead/Cake.Bridge.DependencyInjection
- NuGet - nuget.org/packages/Cake.Bridge.DependencyInjection
This post is licensed under a Creative Commons Attribution 4.0 International License