On 4 February 2013 15:50, Adam Murdoch <[email protected]> wrote:

>
> On 05/02/2013, at 5:12 AM, Daz DeBoer wrote:
>
> On 4 February 2013 00:07, Adam Murdoch <[email protected]>
> wrote:
>
> Hi,
>
>
> So, we're planning to have a bunch of 'jvm binaries' that can be built from
>
> various language source sets and other things. There will be a few
> different
>
> types of binaries, such as class directory binaries and jar binaries,
>
> possibly some others.
>
>
> Something we need to sort out is how to structure the DSL for these
>
> executable things. The current plan is to have a single container that owns
>
> all of these jvm binaries, so you might declare something like this:
>
>
> jvm {
>
>    binaries {
>
>        mainClasses(ClassesDirectoryBinary) {
>
>            … some inputs and other configuration ...
>
>        }
>
>        mainJar(JarBinary) {
>
>            … some inputs and other configuration …
>
>        }
>
>    }
>
> }
>
>
> There might be a similar container for native binaries:
>
>
> native {
>
>    binaries {
>
>        windowsX86DebugShared(SharedLibraryBinary) {
>
>            … some inputs and other configuration …
>
>        }
>
>        windowsX86DebugStatic(StaticLibraryBinary) {
>
>            ...
>
>        }
>
>        windowsX86DebugExe(ExecutableBinary) {
>
>            …
>
>        }
>
>    }
>
> }
>
>
> Some questions:
>
>
> * Is using a flat name the best way to identify these things? Once you add
> a
>
> few dimensions, the names start to get awkward. This is certainly can be
> the
>
> case for native binaries, and can also be the case for jvm binaries. For
>
> example, I might have (feature, binary type, groovy version, jvm version)
> as
>
> relevant dimensions for a Groovy library that targets multiple groovy
>
> versions and jvm versions.
>
>
> Are the names of these things important at all? Or in general are we
> just forcing users to come up with a name that adds little value?
>
>
> I think it varies for different types of things. For some things, a name
> is a natural way of identifying the thing. For other things (most things?)
> it makes more sense to identify a thing by its type and some attributes
> about the thing.
>
> The complication is that the set of attributes that identify a thing vary
> based on what I'm building. For example:
>
> * If I have a single publication, then I want to refer to it as 'the
> publication'. The other stuff (type, groupId, artefactId, version) are just
> attributes of the publication.
> * If I publish 2 maven modules, then I want to refer to them as the 'api
> publication' and the 'impl publication', say.
> * If I build debug and release variants of my windows executable, then I
> want to refer to them as the 'debug executable' and the 'release
> executable'. All the other stuff (windows, amd64, multi-threaded,
> visual-c++ compiler, optimisation-level) are just attributes of the
> publication.
> * If I build debug and release variants on windows and linux for x86 and
> amd64, then I want to refer to them using a tuple such as (windows, amd64,
> release).
>
> That is, a thing often just has a bunch of attributes, any of which could
> be used to identify it, and it's how the thing is different to the others
> that is useful for identifying it.
>

Right, so it "name" just another one of those ways of identifying?
Sometimes I want to give something a meaningful name, sometimes forcing me
to come up with a name is a pain in the ass.


> One nice aspect of ditching the name is that a thing can more naturally
> live in different containers and be grouped in different ways. Which would
> mean that some of these questions about how things are grouped become less
> important - just group them whichever way you like.
>
>
> How
> often does a user need to differentiate between them by name?
>
>
> There are a few main reasons, I think:
>
> 1. To configure something that some other logic (a plugin, say) has
> already defined.
> 2. To configure the tasks that do work with the thing (compile it,
> generate the pom.xml for it, publish it).
> 3. To find the thing to use it as input for some other thing.
> 4. To refer to the thing before the 'identifying' attributes have been
> calculated. For example, to refer to a publication before the version has
> been calculated.
>
> None this necessarily requires a name - this is just what the name is used
> for at the moment.
>

And I'm not sure any of these are the 'standard' case either. Again I refer
to repositories: imagine that we used the new "name(Type)" syntax. Users
would be forced to come up with a name for each of their repositories,
which would likely not be used elsewhere. Instead, we give the ability to
supply a name _if_ they want to refer to the repository elsewhere.

One thing that concerns me about the "name(Type) {}" syntax is that it's
possibly trickier to document, and trickier for users to grok what's going
on. In some cases it might make for a cleaner DSL, but I'm not certain it's
worth the cost.

> We could consider a DSL similar to the repositories syntax:
>
> jvm {
>    binaries {
>        classes {
>            name "main" // optional
>            … some inputs and other configuration ...
>        }
>        jar {
>            ... we generate a sensible name ...
>            … some inputs and other configuration …
>        }
>    }
> }
>
> It's possible that we treat this as a standard pattern, whereby a
> NamedDomainObjectContainer could support both with some sort of DSL
> magic:
>
> container {
>      name(Type) {}
>      subtype { // generated name }
> }
>
> Or maybe get rid of the 'name' method altogether, and go with:
>
> // In all cases the added element must provide a unique name, which
> may or may not be configured explicitly.
> container {
>       generalType(SubType) {} // eg 'publication' for 'publications'
> container, or 'dependency' for 'dependencies' container.
>       subType { } // eg 'ivy' for 'publications' or 'project' for
> 'dependencies'
> }
>
>
> These are both interesting options for defining things. One question is
> how do I get something out again, to either configure it or use it?
>

There would be options:
container.findOne({attrib == "value"})
container.findOne(attrib1: "value", attrib2: "value")
container['name']
container.name

Note that I'm not suggesting doing away with "name" altogether, but instead
making it optional. It would come from
- method name if we think supporting the "name(Type) {}" syntax is a good
idea
- 'name' attribute supplied in the configuration closure
- generated from attributes if none explicitly supplied

In general, I guess you'd be likely to specify a name if you wanted to use
it for later reference.

- Does 'name' remain immutable after addition? If so, then any generated
name would probably need to be based on type only. This would be a bit
unfortunate, since it would be nice to name a publication after the
module-name in many cases.
- Does 'name' need to be unique? Or is this only mandated when we later
attempt to access by name?

I would say the simplicity of unique and immutable are probably worth the
cost.


>
>
> * What do we do with specialised types of jvm binaries, that run on the jvm
>
> but which require a certain runtime and that are packaged in a certain way:
>
> a WAR or exploded J2EE web app or an OSGi bundle or Gradle plugin?
>
>
> * Is the separation between jvm binaries and native binaries useful? Should
>
> there be a single `binaries` container? Or should it be finer-grained to
>
> include type, so that there is a `jvm.binaries.classes` and a
>
> `jvm.binaries.jar` container and a `native.binaries.staticLibs` container?
>
> Is the type of runtime actually less important than the type of thing, so
>
> that it should be `binaries.jvm` and `binaries.native`?
>
>
> Where would combined-and-optimised javascript fit into this model?
> What about shell-scripts that are tailored for a runtime?
>
>
> If we consider these things as binaries (and we might), then the answer to
> this depends somewhat on the question about specialised binaries, above.
> Javascript 'binaries' would target a different type of runtime, just like
> jvm and native binaries target different types of runtimes. Shell scripts
> might be better treated as a way of packaging a command-line application,
> as either a 'native' or maybe a more specialised 'shell' binary.
>
> I think a question we need to answer is whether there is something common
> here between all these things, either as an abstraction or a pattern, or
> whether it's all just coincidence.
>
> So far, we've been using the term 'binary' in a pretty abstract way, to
> mean 'something that can run on a particular runtime', where 'runtime' is
> some abstract environment or container. The idea is that both binaries and
> runtimes will be typed in some way.
>
> If we think that the abstract model is a good idea, then do we jam all
> binaries into the same container? Do we group them by runtime? By role? By
> runtime 'family' (e.g. 'jvm', 'native', 'javascript')? By type? Something
> else?
>
>
>
> Maybe we need a few more use cases to flesh out the DSL.
>
>
> There are plenty. Any ideas what would be useful?
>
>
> Or would
> these be declared in a different container?
>
>
> Very similar questions to source sets, re. how to arrange them and which
>
> dimension wins over the others and which need to be encoded in the name and
>
> which are encoded in the structure. Maybe we should rethink our container
>
> DSL a bit more deeply. The publications would also benefit from have a
>
> composite identifier (e.g. groupId, artifactId, version).
>
>
> Yes I think this could benefit from a re-think - the current proposed DSL
> is:
>
>    publications {
>        myPublication(IvyPublication) {
>            organisation 'my-organisation'
>            module 'my-module'
>            revision '1.2'
>        }
>    }
>
> The only thing the name "myPublication" is currently used for is
> generating task names. Other than that, it adds little value. We will
> be enforcing that the org:module:revision is unique, and this is
> really how the publication is identified.
>
> In that case, something like the last option above might work better:
>
>    publications {
>        ivy {
>            organisation 'my-organisation'
>            module 'my-module'
>            revision '1.2'
>        }
>
>
> For most publications, these attributes can be inferred. Is the idea that
> you define the full identifier, or just describe how it's different to the
> default?
>

I think inferred is fine. So what would the 'name' of the ivy publication
be?

- "publications['main'] has appeal, but doesn't work well as soon as
another is added.
- publications['my-module'] is nice, but it's certainly possible to have
multiple publications with the same module/artifactId
- publications['IvyPublication1'] is probably the only option that is
simple and just works.

Of course, if you do want to refer to a particular publication elsewhere,
you're better off explicitly specifying a name in the configuration
closure. Or possibly you'd use:

publications.findOne(module: 'my-module')

-- 
Darrell (Daz) DeBoer
Principal Engineer, Gradleware
http://www.gradleware.com

Reply via email to