Longs, Original

Cake.Console 1.2.0

After a bit of work, I have found Cake.Console stable enough for a first release. I decided to version it with the same number as Cake itself. If needed I will update the revision number.

Usage

Create a new project referencing Cake.Console. It will look something like this

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <OutputType>exe</OutputType>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Cake.Console" Version="1.2.0" />
  </ItemGroup>
</Project>

Add a single Program.cs file with the code. Take advantage of top-level statements.

There are 2 ways of using Cake.Console:

  1. Building an IScriptHost. This is the implicit object in the .cake scripts, so we can use it to register tasks, perform setup, etc.
var host = new CakeHostBuilder().BuildHost(args);

host.Setup(() => { do something });
host.Task("TaskName").Does(c => c.Information("Hello"));
host.RunTarget(host.Context.Arguments.GetArgument("target"));
  1. Using the Cake Cli, that includes arguments like –target, –version, –info, –tree, –description, –exclusive…
    It’s very similar to frosting
new CakeHostBuilder()
    .WorkingDirectory<WorkingDirectory>()
    .ContextData<BuildData>()
    .RegisterTasks<CakeTasks>()
    .InstallNugetTool("NuGet.CommandLine", "5.9.1")
    .RunCakeCli(args);

In this case, we dont have access to the host, so we need to define the build with the 4 extensions that come with Cake.Console:

  • WorkingDirectory<>
  • RegisterTasks<>
  • ContextData<>
  • InstallNugetTool

WorkingDirectory<>

Here we can use a class that has the interface IWorkingDirectory and implements the string WorkingDirectory property.

The class can receive in the constructor any part of the cake infrastructure (ICakeContext, ICakeLog, ICakeArguments, ICakeConfiguration…)

RegisterTasks<>

Here we can use a class that has the interface ICakeTasks.

The class can receive in the constructor any part of the cake infrastructure (ICakeContext, ICakeLog, ICakeArguments, ICakeConfiguration…)

All the methods that have the signature void Name(CakeTaskBuilder builder) will be called, and the name of the method will be the name of the task.

ContextData<>

Here we can use any class that will then be available for use in the task’s definitions.

InstallNugetTool

Given a package name and a version, installs a nuget package as a Cake tool

Summary

Putting it all together

using Cake.Common.Diagnostics;
using Cake.Console;
using Cake.Core;

new CakeHostBuilder()
    .WorkingDirectory<WorkingDir>()
    .ContextData<ContextData>()
    .RegisterTasks<CakeTasks>()
    .InstallNugetTool("xunit.runner.console", "2.4.1")
    .RunCakeCli(args);

record WorkingDir(string WorkingDirectory = ".") : IWorkingDirectory;

class ContextData
{
    public string SomeVeryImportantData { get; set; } = "Cake is awesome!";
    public ContextData(ICakeArguments args)
    {
        if (args.HasArgument("tone-down"))
        {
            SomeVeryImportantData = "Cake is pretty good...";
        }
    }
}


class CakeTasks : ICakeTasks
{
    private readonly ICakeContext ctx;

    public CakeTasks(ICakeContext ctx) => this.ctx = ctx;

    public void TaskName(CakeTaskBuilder b) => b
        .Description("Some task")
        .Does(() => ctx.Information("Something"));

    public void AnotherTask(CakeTaskBuilder b) => b
        .IsDependentOn(nameof(TaskName))
        .Does<ContextData>(data => ctx.Information(data.SomeVeryImportantData));
}
Longs, Original

Presenting Cake.Console

I wanted to run Cake inside a console app, without the penalty of pre-processing the .cake DSL, and have the all the power of an IDE (refactorings, find usages,…). I had 2 possibilities:

  1. Cake.Frosting
    This was the best option, but I really didn’t like a couple of things like, the ceremony of writing a class for each task or using attributes for describing tasks instead of the fluent syntax of cake scripts
  2. Cake.Bridge
    This was more in line with what I wanted, but It missed some stuff like tool installing.

So, it was time to roll up my sleeves and get to work. Presenting Cake.Console!

var cake = new CakeHostBuilder(args)
    .InstallNugetTool("xunit.runner.console", "2.4.1")
    .Build();

cake.Task("Hello")
    .Description("This is just like a cake script")
    .IsDependeeOf("World")
    .Does(c => c.Information("but methods are on the 'cake' object"));

cake.Task("World")
    .Does(c => c.Information("Hello world"));

var target = cake.Context.Argument("target", "hello");
cake.RunTarget(target);

It’s a fairly simple project, but I learned a lot about cake’s internals.

Cake has an architecture where every piece of functionality is behind an interface and is injected into objects as needed. Then the registering of interfaces into implementations is defined in “Modules”. There is a ICakeContainerRegistrar Object that can receive registrations. I needed to implement a registrar if I wanted to take advantage of internal implementations of interfaces from Cake. So I did create a CakeContainer that can receive registrations from Cake.Core and Cake.Nuget modules and then create an IServiceProvider that can instantiate the needed parts of cake.

After understanding this part, It’s just a case of wiring some moving parts and I got it to work. The only “hand coded” part was the parsing of commandline arguments, which was done very naively.

What I got was a piece of code that can give me a IScriptHost object, which is the implicit object that is called on .cake scripts when we define Tasks or use Addins.

I still needed one thing, the installation of tools. I then added 2 things, a way to register stuff into the ICakeContainerRegistrar and a special interface IHostBuilderBehaviour that executes a Run() method before returning the IScriptHost, to add functionality into Cake.Console. What I got was a very simple CakeHostBuilder that I can then extend via extension methods.

With all this infrastructure in place I then added 5 extensions that fulfilled all my needs in this project

Installing Tools

I added the interface ICakeToolReference, and the ToolInstallerBehaviour. Created also a CakeNugetTool class to create the correct Url for a nuget package.
Then it’s just a matter of registering ICakeToolReferences into the ICakeContainerRegistrar

Tasks from methods

I added the ICakeTasks interface and the TaskRegisteringBehaviour, which instantiates the ICakeTasks, and calls all the methods that receive a CakeTaskBuilder. This CakeTaskBuilder will already have created the Task with the same name as the method.

Changing WorkingDirectory

Once more I added the IWorkingDirectory interface which has working directory string a and the WorkingDirectoryBehaviour, that converts it to an absolute path and changes the working directory. Useful when your build scripts are not in the same tree as the code itself.

Auto setup context data

The Setup callback on the IScriptHost can return an object that can then be used in the CakeTaskBuilder extensions. This is called a Typed Context. I wanted a typed context that could tap into the internals of cake, so it needed to be registered into the ICakeContainerRegistrar.

Once more I created a SetupContextDataBehaviour, and I’m good to go. I can even register multiple typed context and use the needed one on different tasks.

Run target

I found myself hating that part of the script that reads the “target” from the arguments. It just breaks the fluent vibe from the code! So I extended the CakeHostBuilder to have a Run method that simply reads the target from the arguments and runs it. Putting it all together…

All modesty aside, I really think it is looking great!

Quotes, Shares

The very fact that I am writing this book may well, from the perspective of history, be at least in part traceable to the phenomenal energy, ability, and courage of Luther, Calvin, and other Reformers–figures who inspired and achieved the monumentally important task of bringing Scripture back into the centre of Christianity and its witness to the world. Their emphasis on the glory and sovereignty of God, and their insistence on constantly going back to the biblical text–taking great pains to explain it clearly and only accepting what was consistent with it–form a model to which many of us lesser mortals rightly aspire. Following that lead has been a great inspiration to many Christians today, myself included, who long for more solidity, more intellectual depth, more maturity in the expression of their Christian faith, more sense of God’s holiness and more concern for God’s reputation than is to be found in some of the frothy, insubstantial attempts to make the Christian faith more attractive to the outside world.

John Lennox – Determined to Believe?
Original, Shorts

Ballads of the Exodus

https://www.balladsoftheexodus.com/

Não é o filme típico. Em 1º lugar tem 2 partes, são mais de 4 horas de filme com um interlúdio no meio, em 2º lugar praticamente não tem diálogo – é quase um musical? – e por fim não tenta reproduzir fielmente a época da história original, com grandes anacronismos introduzidos propositadamente.

Não é nada do que estava à espera mas no entanto gostei. É incrível como ler nos pode dar muito detalhe e precisão, mas nada bate a 7ª arte para capturar a imaginação e fazer-nos entrar na história.

Music, Shares

Jimmy Smith, Cannonball Adderley, Dave Brubeck and Charlie Mingus live • 31-10-1971

Unique recordings of Jimmy Smith, the Cannonball Adderley Quintet featuring George Duke, Dave Brubeck & his Trio with Gerry Mulligan and Paul Desmond,and the Charles Mingus Sextet featuring Cat Anderson at the 7th Newport Jazz Festival at the Doelen, Rotterdam, The Netherlands, 1971.

• 00’00” Hammond organist Jimmy Smith and his band, featuring among others the illustre Illinois Jacquet and James Moody on tenor saxophone and Art Farmer on flugelhorn, Kenny Burrell on guitar, Clark Terry on bugel and Roy Haynes on drums. A unique recording!
• 05’36” The Cannonball Adderley Quintet featuring Julian Edwin ‘Cannonball’ Adderley, alto saxophone; Nat Adderley, cornet; George Duke, keyboards; Walter Booker, bass; Roy McCurdy, drums.
• 22’50” Dave Brubeck Trio performs a great concert with his sidemen Jack Six, bass and Allan Dawson, drums. The trio is completed with alto saxophonist Paul Desmond and baritone saxophonist Gerry Mulligan.
• 49’32” The concert is followed by an exerpt of the concert of the Charles Mingus Sextet with Cat Anderson on trumpet at the same 7th Newport Jazz Festival This is part two of the recordings of the 7th Newport Jazz Festival 1971.

The recording was made 31st October 1971 at the Doelen Concert hall, Rotterdam, The Netherlands.

Music, Shares

Neighborhood Bully – Bob Dylan

I’m not a big Dylan fan, but he sure had a way with words…

Well, the neighborhood bully, he’s just one man
His enemies say he’s on their land
They got him outnumbered about a million to one
He got no place to escape to, no place to run
He’s the neighborhood bully.

The neighborhood bully he just lives to survive
He’s criticized and condemned for being alive
He’s not supposed to fight back, he’s supposed to have thick skin
He’s supposed to lay down and die when his door is kicked in
He’s the neighborhood bully.

The neighborhood bully been driven out of every land
He’s wandered the earth an exiled man
Seen his family scattered, his people hounded and torn
He’s always on trial for just being born
He’s the neighborhood bully.

Well, he knocked out a lynch mob, he was criticized
Old women condemned him, said he could apologize
Then he destroyed a bomb factory, nobody was glad
The bombs were meant for him. He was supposed to feel bad
He’s the neighborhood bully.

Well, the chances are against it, and the odds are slim
That he’ll live by the rules that the world makes for him
‘Cause there’s a noose at his neck and a gun at his back
And a license to kill him is given out to every maniac
He’s the neighborhood bully.

Well, he got no allies to really speak of
What he gets he must pay for, he don’t get it out of love
He buys obsolete weapons and he won’t be denied
But no one sends flesh and blood to fight by his side
He’s the neighborhood bully.

Well, he’s surrounded by pacifists who all want peace
They pray for it nightly that the bloodshed must cease
Now, they wouldn’t hurt a fly. To hurt one they would weep
They lay and they wait for this bully to fall asleep
He’s the neighborhood bully.

Every empire that’s enslaved him is gone
Egypt and Rome, even the great Babylon
He’s made a garden of paradise in the desert sand
In bed with nobody, under no one’s command
He’s the neighborhood bully.

Now his holiest books have been trampled upon
No contract that he signed was worth that what it was written on
He took the crumbs of the world and he turned it into wealth
Took sickness and disease and he turned it into health
He’s the neighborhood bully.

What’s anybody indebted to him for ?
Nothing, they say. He just likes to cause war
Pride and prejudice and superstition indeed
They wait for this bully like a dog waits to feed
He’s the neighborhood bully.

What has he done to wear so many scars ?
Does he change the course of rivers ? Does he pollute the moon and stars ?
Neighborhood bully, standing on the hill
Running out the clock, time standing still
Neighborhood bully.