Home > Software design >  How to pass command line arguments to Cake (Frosting), when these arguments are already collected wi
How to pass command line arguments to Cake (Frosting), when these arguments are already collected wi

Time:09-16

I'm developing a .net tool for building our projects. I'm using System.CommandLine package for collect command line argument without sweat. My build command looks like this:

    [Command(Description = "Runs build process")]
    public class Build
    {
        public int Execute(
            [Option] string targetDirectory,
            [Option(Aliases = new[] {"-c"})] string configuration = "Release")
        {
            return new CakeHost()
                .UseContext<BuildContext>()
                .Run(Enumerable.Empty<string>());
        }
    }

Note that there are attributes not available in the Microsoft's library. It's my addition. Type is converted into Command on the fly.

The important thing is that Cake takes arguments only as string collection. So the only way I can see here, is to convert arguments into strings and parse it again inside a task. I will not able to sleep for a month if I do that.

The solution I would expect here is to create and pass an instance of BuildContext type (it inherits from FrostingContext). I could simply have properties corresponding to app arguments.

Any ideas how to workaround it? Or maybe there is a feature I don't know?

CodePudding user response:

To achieve this you could use dependency injection to inject your custom arguments into your own build context as a singleton.

This could look something like

[Command(Description = "Runs build process")]
public class Build
{
    public int Execute(
        [Option] string targetDirectory,
        [Option(Aliases = new[] {"-c"})] string configuration = "Release")
        => new CakeHost()
                    .ConfigureServices(services => services.AddSingleton(new BuildParameters(targetDirectory, configuration)))
                    .UseContext<BuildContext>()
                    .Run(Array.Empty<string>());
}

In this case, BuildParameters is defined like this

public class BuildParameters
{
    public DirectoryPath TargetDirectory { get; }
    public string Configuration { get; }

    public BuildParameters(string targetDirectory, string configuration)
    {
        Configuration = configuration;
        TargetDirectory = DirectoryPath.FromString(targetDirectory);
    }
}

A minimal FrostingContext utilizing this

public class BuildContext : FrostingContext
{
    public BuildParameters BuildParameters { get; }

    public BuildContext(ICakeContext context, BuildParameters buildParameters)
        : base(context)
    {
        BuildParameters = buildParameters;
    }
}

And then in all your Frosting tasks, you'll have a BuildParameters property you can access like this.

[TaskName("Hello")]
public sealed class HelloTask : FrostingTask<BuildContext>
{
    public override void Run(BuildContext context)
    {
        context.Log.Information("Configuration {0}", context.BuildParameters.Configuration);
    }
}

CodePudding user response:

I feel you have two ways to go about this:

If you want to use Cake Frosting, which is meant to parse command line arguments, you'd have to pass all the arguments you are given, something like

new CakeHost()
 .UseContext<BuildContext>()
 .Run(new[]
  {
    $"--configuration={configuration}"
  });

(Alternatively, you could check if System.CommandLine contains a feature to access the arguments "raw" as they were given.)

Or, if you want to do all the parsing and setup in "your" app, you should have a look at Cake.Bridge which allows for using Cake-features fully programmatically. (IMHO this is the longer/harder path)

  • Related