Can I remove a ('additional' type) property from a Project?


(Blaine Simpson) #1

I understand from the API spec for the Project class that the properties are dynamic, and I don’t expect to be able to remove properties that come from method getters, super-projects, etc., but the additional properties is just a Map of arbitrary name/value pairs. Seems to me that the ability to remove elements from any provided Map should be a rudimentary capability.

Since some properties are dynamic (i.e. non-additional), and the fact that .remove has no effect on the project, I suspect that Project.getProperties() returns a copy of the additional map, but I can’t test due to GRADLE-1935.

task testPropRemoval << {
    project.propA = 'alpha'
    assert project.hasProperty('propA')
    /* Can't test this due to GRADLE-1935, which I just opened:
    print '''Project.getProperties return a 'copy' of map?
'''
    println project.properties.hashCode() != project.properties.hashCode()
    */
    println 'What is being remove?... ' + project.properties.remove('propA')
    print 'Does project still have the property that I removed?
'
    println project.hasProperty('propA')
}

(Luke Daley) #2

Aside: comparing hashcodes of maps doesn’t check for identity. To do that you should do…

project.properties.is(project.properties)

For the main issue. It’s not that simple as the “properties map” is somewhat virtualised and doesn’t reflect the underlying storage. That said, we could use a custom Map implementation that knows about all of the different types of underlying storage and tries to implement the remove. But, I think we’d need a strong use case for this as it would be a lot of work.

There is an internal API for removing “additional” properties though.

project.additionalProperties.remove(“propA”)

That should work I think. But, it is internal API so is subject to change without notice.

Perhaps you could explain what the problem is your trying to solve as there may be a different way around this. Or, could give impetus to making ‘getAdditionalProperties()’ part of the public API.


(Blaine Simpson) #3

Thanks for the tip about the is operator, Luke.

Re. my immediate need, I am enhancing a plugin of mine. The main purpose is to add new properties to the Gradle project in general and convenient ways. For completeness, I’d like to give my users the ability to remove properties that they have added too. Definitely not a big deal for me, as I can just document the limitation, and why.

More generally, I manage many cross-platform development projects and I do a lot of scripting to set up portable and idiot-proof build environments. One thing that I frequently want to do is clean up an environment, like in Ant I would clear CLASSPATHs and set relevant options. A tool as general as Gradle should give me the ability to unset/remove properties that have been set. I.e., it’s just bad behavior to have an assignment (with much understandable behavior expectation for the average Java developer) like ‘project.x = 3’, result in a permanent and irreversable instantiation of project.x. Not a big deal for me, but I wanted to understand whether it is possible or not (to unset Gradle additional properties).

Gradle’s little deviations from expected behavior causes political problems for me. I evangelize to convert projects over to Gradle, and I too often find myself challenged by associates who are also senior build system experts or developers, and who point out these weaknesses. (By far the challenge that shuts me down most often is that Gradle still does not generally support honoring specified task dependency sequences, per GRADLE-427, but that’s another subject…).


(Luke Daley) #4

It’s not advisable to add too many properties to a project (or any other model element) instance. In the future we’ll be strongly advocating stronger modelling by the use of extensions which are kind of like namespaced mixins.

That said, they aren’t quite documented yet so I can’t point you at any docs. If you are interested though, you can check out how they are used in the core.


(Blaine Simpson) #5

Makes sense to avoid unnecessary namespace pollution, risking conflicts and so forth.

At some point I’ll generalize my system to target the object to load the properties into (liek an extension object) instead of just loading into the Project.

Thanks for the input, Luke.


(Adam Murdoch) #6

Extensions are documented in the user guide: http://gradle.org/current/docs/userguide/custom_plugins.html#N149B1


(Blaine Simpson) #7

I’m familiar, but thanks… and thanks for the great plugin system. Busy building plugins for the past couple days.


(Blaine Simpson) #8

Advice request. I want to know if there is anything wrong with my plan to enhance my properties-file-loader so that it can configure arbitrary specified plugins via Java properties files.

I very much like configuring with Java Properties files as much as possible, understanding that it is just unapplicable for many cases. I already have a type-smart plugin so I can set like

xfer.destFile(File)=output.txt
xfer.maxXferTime(Float)=3.124
javac.debug(Boolean)=false

I just thought up a design so that I can configure simple properties of extension files with Java properties files. (Simple meaning that nested and collection fields will not be supported). A single properties file can be targeted to a specified extension object, or each property name can be prefixed with the extension name, like so:

xferPuginExtObject$destFile(File)=output.txt
xferPluginExtObject$maxXferTime(Float)=3.124

Either way, the assignments will be made when I load the property files, if the target extension object is available then. Otherwise my plugin will store the settings, and they will be applied when other plugins apply (via whenPluginAdded callback).

For any reason is this configure-plugin-by-Java-properties-file goal a bad idea?


(Blaine Simpson) #9

Nobody objected, so I did it.

Made following enhancements to my JavaPropFile plugin to support goal to minimize usage of Project property namespace. * System property settings require use of a namespace prefix to clearly distinguish * Can use {{.}} as property-dereference operator, just like in Groovy, to access or set nested properties like {{java.options.debug}}. * Can use a specified extension object as the root object (containing property or nested property) instead of the Project. * Can default an entire properties file being read to a specified extension object instead of the Project.

I withdraw my qualification that “nested and collection fields will not be supported”, because they now are.