adamralph / bau

The C# task runner
MIT License
152 stars 17 forks source link

[Radical] Allow for scripting languages other than ScriptCS #214

Open eatdrinksleepcode opened 9 years ago

eatdrinksleepcode commented 9 years ago

ScriptCS is a great way for developers who primarily use C# to easily create a minimal build script using a familiar syntax. And Bau has done a great job with the fluent interface of keeping the highly imperative nature of C# from having a negative impact on the DSL.

That being said, when coming from dynamic scripting languages such as Groovy (for Gradle) or Ruby (for Rake) or JavaScript (for Grunt), even ScriptCS still feels overly verbose and not easy to read when used in this kind of scripting context. I would love to be able to use the other (very few) CLR languages that are more scripting-oriented (in particular, I am interested in Boo, which is not dynamic but does have syntax features that make it more attractive than C# for scripting).

In practical terms, this would mean separating the model (primarily BauTask) and the execution engine (primarily Bau.Run and its dependencies) from the syntax that constructs and executes the model out of the build script (most of the Bau class). The model and execution engine should not have any references to ScriptCS.

Note that this issue is NOT about removing support for ScriptCS, or even replacing it as the primary scripting language. ScriptCS as the primary language is perfectly reasonable and there is no reason to change that. Note also that this issue is NOT about actually implementing any alternative scripting languages. It is just about creating a clean separation between the construction of the model and the execution of the model, such that constructing the model via other scripting languages is more tractable.

eatdrinksleepcode commented 9 years ago

If we think factoring Bau in this way makes sense, I can start working on it. Since it is a fairly invasive breaking change to core types, the sooner we do it, the less painful it will be.

I envision the current Bau project being split into two projects: Bau.Core and Bau.ScriptCS. Even if we end up publishing the latter under the package name Bau (to make it easy to identify as the primary entry point for using Bau), I think using the ScriptCS identifier on the project name still makes sense. Bau.Core would contain the model and the execution engine, and Bau.ScriptCS would contain the ScriptCS-specific interface for generating the model and invoking the execution engine.

Does that make sense? I can always take a stab at it and we can iterate as we go.

adamralph commented 9 years ago

This is an interesting one.

I did think about splitting the scriptcs parts of Bau into a tiny assembly of their own a while back since the main body of Bau really has nothing to do with it. I think the reason I didn't was because I didn't really see a need and also because of the awkwardness of naming, i.e. the top level package should then really be Bau.ScriptCs, taking a dep on Bau, but I think this could be solved, even if it means an awkward upgrade path for one release.

So the main consideration then is, is there a need? Bau has always taken the view that scriptcs is the platform, not .NET. This means all concerns such as execution, language, BCL etc. are all controlled by, and provided from, scriptcs, much in the way that grunt and gulp are completely dependent on nodejs, and see nothing outside, or below, that universe. So my initial question would be, could you write a Boo engine for scriptcs? We've already done this for several other languages. Currently in dev we have VisualBasic, based on the new Roslyn, the F# engine has been around for a while (although may be currently broken) and @filipw has put together demo engines for things as obscure as lolcode and brainfuck.

I've just remembered, there are more considerations. First of all, the Bau plugins, e.,g. Xunit and MSBuild, are also scriptcs script packs and they inherit from BauTask which gives them the script pack wire up, i.e. you don't have to Require<BauXunit> or using Bau.Xunit;. It all happens auto-magically. If we decouple the core from scriptcs then plug in authors would also have to provide a script pack package on top of a core non-scriptcs package in order that the plug-ins carry the same level of portability as Bau core, otherwise you end up with no plugins to use as soon as you step outside scriptcs. Secondly, we are edging closer to a script-only ecosystem for scriptcs. Currently we script libraries, and later, if you follow the developments of the new Roslyn scripting bits, this is probably going to become a first class feature of Roslyn and even C# itself, which means Bau may potentially cease to be a compiled assembly and become a set of scripts instead, very much analogous to a node module.

eatdrinksleepcode commented 9 years ago

If we decouple the core from scriptcs then plug in authors would also have to provide a script pack package on top of a core non-scriptcs package in order that the plug-ins carry the same level of portability as Bau core...

Yeah this is the first thing I noticed when I started playing around with decoupling them. It is unfortunate that scriptcs relies on inheritance in order to achieve automatic namespace imports; if it were based on a simple attribute we would get a lot more flexibility.

we are edging closer to a script-only ecosystem for scriptcs...

What is the advantage of this approach? I can see being able to create plugins as simple scripts is advantageous for the end user, but Bau will be a Nuget package either way, right? So the only advantage that I see is that we get to skip the compile step in our build, at the cost of forcing end users to compile (or interpret or whatever) the script files during their build. That doesn't feel like a good tradeoff. What else am I missing?

could you write a Boo engine for scriptcs?

I have no idea. If it can be done for other languages, I imagine it could be done for Boo. It is worth looking into. Since Boo already has its own mechanisms for scripting I had hoped to take advantage of that and not have to write another layer.