New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide type-safe accessors for contributed extensions #159

Closed
bamboo opened this Issue Oct 18, 2016 · 3 comments

Comments

Projects
None yet
3 participants
@bamboo
Member

bamboo commented Oct 18, 2016

plugins {
    application
}

application { // type-safe extension member automatically generated by Gradle Script Kotlin
   mainClassName = "my.App"
}

@bamboo bamboo added this to the 0.5.0 milestone Oct 18, 2016

@bamboo bamboo changed the title from Provide type-safe accessors to contributed extensions and conventions to Provide type-safe accessors for contributed extensions and conventions Oct 18, 2016

@oehme

This comment has been minimized.

Show comment
Hide comment
@oehme

oehme Oct 18, 2016

Member

I'm curious, how would we know when to create these extensions? The plugins add them at runtime, so does that mean we execute them in order to give auto completion?

Member

oehme commented Oct 18, 2016

I'm curious, how would we know when to create these extensions? The plugins add them at runtime, so does that mean we execute them in order to give auto completion?

@bamboo bamboo modified the milestones: 0.6.0, 0.5.0 Oct 21, 2016

@bamboo bamboo modified the milestones: 0.6.0, 1.0.0 Nov 24, 2016

@bamboo bamboo modified the milestones: 0.7.0, 1.0.0 Dec 15, 2016

@bamboo bamboo modified the milestones: 0.8.0, 0.7.0 Jan 6, 2017

@bamboo bamboo added the epic label Jan 18, 2017

@eskatos eskatos changed the title from Provide type-safe accessors for contributed extensions and conventions to Provide type-safe accessors for contributed extensions Jan 20, 2017

@eskatos

This comment has been minimized.

Show comment
Hide comment
@eskatos

eskatos Jan 20, 2017

Member

Gradle provide two distinct extension mechanisms: Extensions and Conventions.

Extensions allows to extend a type, e.g. Project, with "namespaced" extensions.
For example, the application plugin adds a DistributionContainer as a Project extension, named distributions that you can use as follows:

distributions {
    main {
       contents {
          from(someTask) { into("some/dir") }
       }
    }
}

Conventions allows to extend a type, e.g. Project, with "mixed in" extensions.
For example, the application plugin adds a ApplicationPluginConvention to Project that you ca use as follows:

mainClassName = "com.acme.Main"

At first we considered both but in the light of our findings, see below, this issue only considers Extensions.

https://discuss.gradle.org/t/whats-the-difference-between-plugin-conventions-vs-plugin-extensions/5523

Extensions and conventions are similar (but not identical) ways to dynamically extend the build model. Extensions are the newer concept and have largely replaced conventions. In short, only use extensions, don't use conventions.

An extension is an instance of an arbitrary (typically user-defined) class that's attached to the build model under a user-defined name. The extension class can define arbitrary methods. Assuming it is attached to a 'Project' object, an extension allows you to add 'project.foo.someMethod', but not 'project.someMethod'. Since each extension has its own namespace ('foo' in this case), the chance of name collisions is greatly reduced (compared to conventions).

https://discuss.gradle.org/t/is-the-new-plugin-extension-approach-the-way-to-go/6739

You should prefer the extension mechanism over the convention object mechanism. We will migrate the built-in plugins over time and new plugins will use the extension mechanism. The announce, ide, and c++ plugins all use extensions rather than convention objects.

However, the convention object mechanism is not going away any time soon. We will probably offer some migration mechanism, so that you can use both, and Gradle will warn the plugin users that they should use the new syntax for accessing the properties, rather than the new syntax.

We'll add some way to migrate from convention objects to extensions, so that a plugin can change to using an extension, but users don't have to change their build scripts right away.

This will probably be some method on ExtensionContainer to register the extension as both a convention object and an extension. Gradle will then write a deprecation warning whenever the build script (or some other plugin) attempts to use the object via the convention mechanism.

So, if I have:

apply plugin: 'my-plugin'

myPluginProperty = 'some-value'

and I change 'my-plugin', the above will continue to work, but you get a warning reminding you to change your build script to:

apply plugin: 'my-plugin'

myPlugin { myPluginProperty = 'some-value' }

In the meantime, if you have plugins which use the convention mechanism, it's quite fine to keep using it. The convention mechanism will be supported for a long time. The plan is something like this: 1. Both mechanism supported. Recommend people use extensions. 2. Provide a migration mechanism so that existing plugins can start migration 3. Migrate the built-in plugins 4. After a reasonable migration period, deprecate convention objects 5. After another reasonable migration period, remove convention objects.

We're still at step 1. You don't have to do anything until we finish step 2.

Supporting conventions has been extracted as #250.

Member

eskatos commented Jan 20, 2017

Gradle provide two distinct extension mechanisms: Extensions and Conventions.

Extensions allows to extend a type, e.g. Project, with "namespaced" extensions.
For example, the application plugin adds a DistributionContainer as a Project extension, named distributions that you can use as follows:

distributions {
    main {
       contents {
          from(someTask) { into("some/dir") }
       }
    }
}

Conventions allows to extend a type, e.g. Project, with "mixed in" extensions.
For example, the application plugin adds a ApplicationPluginConvention to Project that you ca use as follows:

mainClassName = "com.acme.Main"

At first we considered both but in the light of our findings, see below, this issue only considers Extensions.

https://discuss.gradle.org/t/whats-the-difference-between-plugin-conventions-vs-plugin-extensions/5523

Extensions and conventions are similar (but not identical) ways to dynamically extend the build model. Extensions are the newer concept and have largely replaced conventions. In short, only use extensions, don't use conventions.

An extension is an instance of an arbitrary (typically user-defined) class that's attached to the build model under a user-defined name. The extension class can define arbitrary methods. Assuming it is attached to a 'Project' object, an extension allows you to add 'project.foo.someMethod', but not 'project.someMethod'. Since each extension has its own namespace ('foo' in this case), the chance of name collisions is greatly reduced (compared to conventions).

https://discuss.gradle.org/t/is-the-new-plugin-extension-approach-the-way-to-go/6739

You should prefer the extension mechanism over the convention object mechanism. We will migrate the built-in plugins over time and new plugins will use the extension mechanism. The announce, ide, and c++ plugins all use extensions rather than convention objects.

However, the convention object mechanism is not going away any time soon. We will probably offer some migration mechanism, so that you can use both, and Gradle will warn the plugin users that they should use the new syntax for accessing the properties, rather than the new syntax.

We'll add some way to migrate from convention objects to extensions, so that a plugin can change to using an extension, but users don't have to change their build scripts right away.

This will probably be some method on ExtensionContainer to register the extension as both a convention object and an extension. Gradle will then write a deprecation warning whenever the build script (or some other plugin) attempts to use the object via the convention mechanism.

So, if I have:

apply plugin: 'my-plugin'

myPluginProperty = 'some-value'

and I change 'my-plugin', the above will continue to work, but you get a warning reminding you to change your build script to:

apply plugin: 'my-plugin'

myPlugin { myPluginProperty = 'some-value' }

In the meantime, if you have plugins which use the convention mechanism, it's quite fine to keep using it. The convention mechanism will be supported for a long time. The plan is something like this: 1. Both mechanism supported. Recommend people use extensions. 2. Provide a migration mechanism so that existing plugins can start migration 3. Migrate the built-in plugins 4. After a reasonable migration period, deprecate convention objects 5. After another reasonable migration period, remove convention objects.

We're still at step 1. You don't have to do anything until we finish step 2.

Supporting conventions has been extracted as #250.

@eskatos

This comment has been minimized.

Show comment
Hide comment
@eskatos

eskatos Jan 20, 2017

Member

Back to extensions.

ExtensionContainer does not allow to list available types keyed by extension name.
ExtensionContainerInternal allows to get all extensions keyed by name, but from that we can't get the actual extension types as eachExtension.getClass() returns their "decorated" type.

ExtensionContainer needs to keep track of each extension registration type and expose that.

Moreover, extensions might have a public type and a different implementation type, possibly also an internal type. ExtensionContainer should allow its clients to register a "public type" for extensions.

See gradle/gradle#1220

Member

eskatos commented Jan 20, 2017

Back to extensions.

ExtensionContainer does not allow to list available types keyed by extension name.
ExtensionContainerInternal allows to get all extensions keyed by name, but from that we can't get the actual extension types as eachExtension.getClass() returns their "decorated" type.

ExtensionContainer needs to keep track of each extension registration type and expose that.

Moreover, extensions might have a public type and a different implementation type, possibly also an internal type. ExtensionContainer should allow its clients to register a "public type" for extensions.

See gradle/gradle#1220

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment