Can I define a reusable subroutine/function/method within a Cake script?
Asked Answered
L

1

5

I'm trying out Cake (C# Make). So far all the examples and documentation have the script file declaring all of its code inside delegates, like this:

Task("Clean")
    .Does(() =>
{
    // Delete a file.
    DeleteFile("./file.txt");

    // Clean a directory.
    CleanDirectory("./temp");
});

However, one of the reasons I'm interested in using Cake is the possibility of writing my build scripts in a similar way to how I write code, as the scripts use a C#-based DSL. Included in this possibility is the ability to separate code that I use into methods (or functions / subroutines, whatever terminology is appropriate) so I can separate concerns and reuse code. For example, I may want to run the same set of steps for a multiple SKUs.

While I realize that I could create my own separate DLL with Script Aliases, I would like to avoid having to recompile a separate project every time I want to change these bits of shared code when working on the build script. Is there a way to define, inline with the normal build.cake file, methods that can still run the Cake aliases (e.g., DeleteFile) and can themselves be called from my Cake tasks?

Lightless answered 17/5, 2019 at 20:58 Comment(0)
D
12

Cake is C#, so you can create classes, methods, just like in regular C#

I.e. declare a class in a cake file

public class MyClass
{
    public void MyMethod()
    {

    }

    public static void MyStaticMethod()
    {

    }
}

and then use it a script like

var myClass = new MyClass();

// Call instance method
myClass.MyMethod();

//Call static method
MyClass.MyStaticMethod();

The Cake DSL is based on Roslyn scripting so there are some differences, code is essentially already in a type so you can declare a method without a class for reuse

public void MyMethod()
{

}

and then it can be called like a global methods

MyMethod();

A few gotchas, doing class will change scoping so you won't have access to aliases / context and global methods. You can get around this by i.e. passing ICakeContext as a parameter to class

public class MyClass
{
    ICakeContext Context { get; }
    public MyClass(ICakeContext context)
    {
        Context = context;
    }

    public void MyMethod()
    {
        Context.Information("Hello");
    }
}

then used like this

// pass reference to Cake context
var myClass = new MyClass(Context);

// Call instance method which uses an Cake alias.
myClass.MyMethod();

You can have extension methods, but these can't be in a class, example:

public static void MyMethod(this ICakeContext context, string message)
{
    context.Information(message);
}


Context.MyMethod("Hello");
Decompress answered 17/5, 2019 at 21:31 Comment(2)
Can the function be declared in a separate file (to keep things neat, and/or to be able to reuse it from another cake script)?Harlene
Yes, use the #load directive for that cakebuild.net/docs/writing-builds/preprocessor-directives/loadDecompress

© 2022 - 2024 — McMap. All rights reserved.