On 05/02/2013, at 7:44 PM, Adam Murdoch <[email protected]> wrote:
> > On 05/02/2013, at 9:33 PM, Luke Daley wrote: > >> >> On 04/02/2013, at 10:50 PM, 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? >> >> It's pretty easy to see the above as a graph rather than a flat space. >> Graphs are notoriously difficult to declaratively navigate though. It would >> have to become predicate based I think… >> >> binaries { >> find(StaticLibraryBinary, { platform == "windows"; debug == true; arch >> = "x86" }) { >> >> } >> } >> >> Hard to see that catching on. > > Because the dsl is kind of awkward? Or some other reason? Awkward DSL. Though, Daz subsequently posted some stuff which improves on the above with some shorthand notations. >> Another option would be to force arranging as a tree and path down… >> >> binaries { >> windows.x86.debug { >> >> } >> } >> >> I don't see that working out though. > > Why's that? Two immediate problems: 1. How do you pick which attribute is the identifier 2. What do you do when your path matches more than one thing at any stage >>>>> 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). >> >> I actually like the “main” paradigm for dealing with the > 1 boundary for >> naming or for irrelevant names. That accurately captures the reality. >> >>> 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. >> >> Which makes selecting via predicate appealing. >> >>> 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. >> >> I can kind of see how we could avoid naming if we completely flipped around >> our current model to be build item based instead of task based (i.e. >> vertices are inputs/outputs and edges are tasks), . That's probably too big >> a change to even entertain the idea of at this point though. > > This is exactly what we're planning to do. There will be a graph of things > and a graph of tasks. The task graph we have to leave as is, but for the > thing graph pretty much anything is an option. And one question there is how > we identity the things in the thing graph. In that case, seems natural to embrace the graphiness. >>>> 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 … >>>> } >>>> } >>>> } >> >> Not a deal breaker, but the assumption that Named things have an immutable >> name runs pretty deep right now. >> >>>> 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? >>> >>>> >>>> >>>>> * 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? >> >> What does having a “binaries” container actually give us? How many such >> containers are we going to end up with? > > Right now, the containers give us 2 things: a way to define a new thing, a > way to find things to do stuff with them. Which means that the containers > need to be a balance between too concrete (makes it harder to find things) > and too abstract (makes it harder to understand and can't infer as much). > > If we were to think about separating these concerns, then we have some other > options. Such as what you've got below. Hmm, will think some more on it. >> Probably going too far again… >> >> If we could make it work, it seems more appealing to simply have one graph >> of things that we can create views of… >> >> items(SourceSet).main { >> >> } >> >> items(StaticLibraryBinary, { platform == "windows" }) { >> >> } >> >> items(JavaScriptBundle, { compressed == true }) { >> >> } >> >> something like… >> >> interface BuildItemContainer extends DomainObjectGraph<NamedBuildable> { >> <T extends NamedBuildable> BuildItemContainer<T> find(Class<T> targetType) >> <T extends NamedBuildable> BuildItemContainer<T> find(Class<T> targetType, >> Spec<? super T> predicate) >> <T extends NamedBuildable> BuildItemContainer<T> find(Class<T> targetType, >> String name) >> } >> >> (Where project has item(*) methods that delegate to project.items.find(*) in >> this case). Everything has a name, but it only needs to be unique in certain >> contexts. One thing about the above is that it would make IDE support a bit >> simpler as we could cut the width of the API that they need to know about >> right down. >> >> Come to think of it, I'm not sure that solves anything that we are talking >> about. >> >>> >>> >>>> >>>> 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? >> >> -- >> Luke Daley >> Principal Engineer, Gradleware >> http://gradleware.com >> >> >> --------------------------------------------------------------------- >> To unsubscribe from this list, please visit: >> >> http://xircles.codehaus.org/manage_email >> >> > > > -- > Adam Murdoch > Gradle Co-founder > http://www.gradle.org > VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting > http://www.gradleware.com > -- Luke Daley Principal Engineer, Gradleware http://gradleware.com --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email
