blog post image
Andrew Lock avatar

Andrew Lock

~5 min read

Simplifying the Cake global tool bootstrapper scripts with .NET Core 3 local tools

In this post I show how you can simplify your Cake global tool bootstrapper scripts by taking advantage of local tools, introduced in .NET Core 3.0.

I described the new local tools feature (introduced in .NET Core 3.0) in a recent post. I'm not going to recap the details of local tools here, so if you haven't already, I strongly recommend reading that post. In this post, I'm going to take the scripts I've been using to bootstrap and run Cake on Windows using PowerShell and Linux using bash or sh, and simplify them by taking advantage of the .NET Core local tools.

Prerequisites

For the scripts shown in this post, I make a few assumptions:

  • Your build environment already has the .NET Core 3.0 SDK installed.
  • You have created a dotnet-tools.json manifest in the default location for your repository (as described in my previous post).
  • You have specified version 0.35.0(or higher) of the Cake.Tool global tool in the tool manifest. This version is compatible with .NET Core 3.0.

If you need to install the .NET Core SDK as well, then I suggest either using one of the more comprehensive Cake bootstrapper scripts, or the official dotnet-install scripts.

You can create a dotnet-tools.json manifest in your project and add the latest version of the Cake tool by running the following from your project's root folder:

dotnet new tool-manifest
dotnet tool install Cake.Tool

The dotnet-tools.json manifest should be checked-in to your source code repository.

A Cake bootstrapper script for PowerShell using .NET Core 3.0 local tools

I always like to have a build.ps1 or build.sh script in a project's root directory, to make it easy to run a full build, whether on a CI machine or locally. With the introduction of local tools to .NET Core 3.0 these scripts have become even simpler:

[CmdletBinding()]
Param(
    [string]$Script = "build.cake",
    [string]$Target,
    [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
    [string[]]$ScriptArgs
)

# Restore Cake tool
& dotnet tool restore

# Build Cake arguments
$cakeArguments = @("$Script");
if ($Target) { $cakeArguments += "--target=$Target" }
$cakeArguments += $ScriptArgs

& dotnet tool run dotnet-cake -- $cakeArguments
exit $LASTEXITCODE

This script essentially only does four things:

  • Define the arguments for the script, to make it easy to specify a Cake script file or a custom target.
  • Restore the local tools using the dotnet-tools.json manifest, by running dotnet tool restore.
  • Parse the arguments provided to the script into the format required by the Cake global tool
  • Execute the Cake global tool by running dotnet tool run dotnet-cake and passing in the arguments parsed in the previous step

In the previous version of the script (for pre-.NET Core 3.0), I installed global tools "locally", which means you have to faff around making sure you have the correct version installed (as you can only "globally" install a single version of a tool). With local tools you can have multiple versions of a tool available, so that all goes away!

To run the script, run .\build.ps1, or pass in a target to run:

> .\build.ps1 -Target=Clean
Tool 'cake.tool' (version '0.35.0') was restored. Available commands: dotnet-cake

Restore was successful.
Running Target: Clean
...

Obviously the bootstrapper script isn't something you're going to have to look at very often, so some complexity in there isn't a big issue. But then again, the less code you have to look after the better!

The script is arguably so simple now, that it's pretty much unnecessary. I would still include it though, as it makes it obvious to consumers of your project how to run the build.

A Cake bootstrapper script for bash using .NET Core 3.0 local tools

Next in line for trimming is the bash bootstrapper script. Previously we had to make sure we installed the correct version of the Cake global tool, and had to work out the required directories etc. With local tools, that all goes away:

#!/usr/bin/env bash

# Define default arguments.
SCRIPT="build.cake"
CAKE_ARGUMENTS=()

# Parse arguments.
for i in "$@"; do
    case $1 in
        -s|--script) SCRIPT="$2"; shift ;;
        --) shift; CAKE_ARGUMENTS+=("$@"); break ;;
        *) CAKE_ARGUMENTS+=("$1") ;;
    esac
    shift
done

# Restore Cake tool
dotnet tool restore

if [ $? -ne 0 ]; then
    echo "An error occured while installing Cake."
    exit 1
fi

# Start Cake
dotnet tool run dotnet-cake "$SCRIPT" "${CAKE_ARGUMENTS[@]}"

This bash script is only doing three steps:

  • Parse arguments
  • Restore the .NET Core local tools
  • Run the restored Cake global tool

This script will work for environments where you have bash available, such as on Debian or Ubuntu distributions. If you're building on the tiny Alpine distribution, you'll need to use the script from the next section instead.

A Cake bootstrapper shell script for Alpine using .NET Core 3.0 local tools

Alpine uses the Almquist (ash) shell instead of bash, so you can't use "bash-isms" like arrays. The script below is a slight modification of the previous script which uses string concatenation in place of arrays:

#!/bin/sh

# Define default arguments.
SCRIPT="build.cake"
CAKE_ARGUMENTS=""

# Parse arguments.
for i in "$@"; do
    case $1 in
        -s|--script) SCRIPT="$2"; shift ;;
        --) shift; CAKE_ARGUMENTS="${CAKE_ARGUMENTS} $@"; break ;;
        *) CAKE_ARGUMENTS="${CAKE_ARGUMENTS} $1" ;;
    esac
    shift
done
set -- ${CAKE_ARGUMENTS}

# Restore Cake tool
dotnet tool restore

if [ $? -ne 0 ]; then
    echo "An error occured while installing Cake."
    exit 1
fi

# Start Cake

dotnet tool run dotnet-cake  "--" "$SCRIPT" "$@"

This version also addresses the use of eval from my previous version of the script. That's not related to local tools, I just finally came across this StackExchange answer that showed how to use set -- to replace the "$@" pseudo-array. That makes me much happier!

Summary

This post showed how you can use the .NET Core 3 global tools feature to simplify your Cake bootstrapper scripts. With a simple JSON file and two .NET Core CLI commands, you can restore and run any .NET Core global tools you need. If you need to install additional tools for your build, you could include them in your manifest file too, or let Cake manage that for you as described here.

Andrew Lock | .Net Escapades
Want an email when
there's new posts?