From 1637ad685977db5b1214f372128725477c55a78a Mon Sep 17 00:00:00 2001
From: Cedric Beust
- The
- This file can also other components which are called plug-in actors. All these actors collaborate with Kobalt
- in order to increase its functionalities. There are two kinds of actors:
+
- All plug-in actors are interfaces and they all extend
- Plug-ins often produce files and data that other plug-ins need to use in order for a build to succeed. For example,
- the Android plug-in needs to generate a file called In order to make things more concrete, let's take a look at
- Kobalt's own
- Kobalt defines a few plug-ins in its core so you never need to download them.
-
- Classpath contributors let you specify additional jar files or directories that will be used by
- the compile task. In the above example, the
-Some plug-ings produce projects (Java, Kotlin) while others don't (Packaging, Application, etc...). The ones that
- do need to register themselves as project contributors. This is how Kobalt collects all the projects defined
- after a build file was parsed.
-
- Kobalt supports the
- You can take a look at the
-
kotlinProject
or dependencies
. These functions typically configure some data that your plug-in will later use to perform its functions.kobalt-plugin.xml
kobalt-plugin.xml
file (stored in META-INF
in the jar file of your plug-in) is mandatory and describes all the components of your plug-in. At a minimum,
- this file will contain the name of your plug-in and the main plug-in class:
+ The kobalt-plugin.xml
file (stored in META-INF
in the jar file of your plug-in) is mandatory and describes all the actors of your plug-in. This file contains a list of class names, each of which is expected to implement at least one of IPluginActor
's interfaces:
<kobalt-plugin>
<name>kobalt</name>
- <plugins>
- <class-name>com.beust.kobalt.plugin.android.AndroidPlugin</class-name>
- </plugins>
+ <plugin-actors>
+ <class-name>com.beust.kobalt.plugin.android.AndroidPlugin</class-name>
+ <class-name>com.beust.kobalt.plugin.java.JavaBuildGenerator</class-name>
+ </plugin-actors>
</kobalt-plugin>
IPluginActors
can be split in several categories:
-
@Task
annotations.IPluginActor
. All interceptors
- extend IInterceptor
and all contributors extend IContributor
+ All plug-in actors are interfaces that extend IPluginActor
. Plug-ins extend IPlugin
,
+ interceptors extend IInterceptor
and contributors extend IContributor
. When Kobalt parses your
+ kobalt-plugin.xml
, it instantiates all the classes found in the <plugin-actors>
tag
+ and then introspects them to find out which IPluginActor
interfaces that class implements.
Contributors
+Plug-in architecture philosophy
R.java
and then make this file available at
- compile time by the Java or Kotlin (or any other language) plug-in. Since plug-ins have no idea about what other
- plug-ins are currently enabled and running, they can't directly talk to each other so instead of calling into
- Kobalt, Kobalt calls into them. This is done by declaring various contributors that Kobalt will invoke whenever
- it needs the information that your plug-in produced. This is a design pattern often referred to as the
- "Hollywood Principle": "Don't call us, we'll call you".
-kobalt-plugin.xml
- and go over it line by line.
-plugins (
-IPlugin
)
- <plugins>
- <class-name>com.beust.kobalt.plugin.android.AndroidPlugin</class-name>
- <class-name>com.beust.kobalt.plugin.application.ApplicationPlugin<class-name>
-
Classpath contributors (
-IClasspathContributor
)
- <classpath-contributors>
- <class-name>com.beust.kobalt.plugin.android.AndroidPlugin</class-name>
- <class-name>com.beust.kobalt.plugin.kotlin.KotlinPlugin</class-name>
-
-
-KotlinPlugin
adds the Kotlin runtime
- to the classpath and Android adds various Android resources (e.g. aar
files) to it
- as well.
-Project contributors (
-IProjectContributor
)
- <project-contributors>
- <class-name>com.beust.kobalt.plugin.java.JavaPlugin</class-name>
- <class-name>com.beust.kobalt.plugin.kotlin.KotlinPlugin</class-name>
-
-Init contributors (
-IInitContributor
)
- <init-contributors>
- <class-name>com.beust.kobalt.plugin.java.JavaBuildGenerator</class-name>
- <class-name>com.beust.kobalt.plugin.kotlin.KotlinBuildGenerator</class-name>
-
---init
command line parameter, which generates a default build file
- based on the files found in the current directory. Any plug-in that wants to be part of this process need
- to specify Init Contributors. In this case, both the Java and Kotlin plug-ins define such a contributor
- but future plug-ins might use this contributor to generate their own build file: Android, Ceylon, Spring, etc...
+ Plug-ins often produce files and data that other plug-ins need to use in order for a build to succeed. For example,
+ the Android plug-in needs to generate a file called R.java
and then make this file available at
+ compile time by the Java or Kotlin (or any other language) plug-in. Since plug-ins have no idea about what other
+ plug-ins are currently enabled and running, they can't directly talk to each other so instead of calling into
+ Kobalt, Kobalt calls into them. This is done by declaring various "actors" that Kobalt will invoke whenever
+ it needs the information that your plug-in produced. This is a design pattern often referred to as the
+ "Hollywood Principle": "Don't call us, we'll call you".
IInitContributor
interface to find out more details but in a nutshell,
- each Init Contributor is asked how many files in the current directory their plug-in handles and the contributor
- with the highest number of files is then asked to generate the build file.
+ These "actors" are exactly what the kobalt-plugin.xml
file describes. This file informs Kobalt about
+ the various ways in which your plug-in participates in the build system by specifying 1) plug-ins, 2) contributors
+ or 3) interceptors.
+
+
IRepoContributor
)- <repo-contributors> - <class-name>com.beust.kobalt.plugin.android.AndroidPlugin</class-name> --
- Some plug-ins might want to add their own repository to the list of repositories that Kobalt already supports.
- This is the case of the Android plug-in which, once the ANDROID_HOME
environment variable has been
- defined, will automatically add the repository inside the Android distribution so that support libraries and other
- artifacts can be found.
-
ICompilerFlagContributor
)- Plug-ins can add flags to the compiler by implementing this interface. -
- -IRunnerContributor
)- Plug-ins that can run a project (task "run") should implement this interface. -
- -ITestRunnerContributor
)- Plug-ins that can run tests (task "test") should implement this interface. + Here is a list of actors (contributors and interceptors) that you can define in your plug-in.
-- Interceptors transform data that Kobalt passes them. -
-ICompilerInterceptor
)- Plug-ins that implement this interface get a chance to alter the arguments that are passed to the various compilers (source files, classpath, arguments, etc...). -
-IClasspathInterceptor
)
- Plug-ins that implement this interface get a chance to alter the dependencies of a project (dependencies{}
, dependenciesTest{}
, ...) before Kobalt sees them.
-
Interface name | +Type | +Description | + +
IBuildDirectoryInterceptor |
+ IInterceptor |
+ + Plug-ins that need to generate class files in a different directory than the default one should + implement this interface. + | +
IClasspathContributor |
+ IContributor |
+ Classpath contributors let you specify additional jar files or directories that will be used by
+ the "compile" task.
+ |
-
IClasspathInterceptor |
+ IInterceptor |
+ + Plug-ins that want to modify the classpath before Kobalt uses it should implement this interface. + | +
ICompilerContributor |
+ IContributor |
+ + Plug-ins that know how to turn files into bytecodes should implement this interface. + | +
ICompilerInterceptor |
+ IInterceptor |
+
+ Plug-ins that implement this interface get a chance to alter the dependencies of a project (dependencies{} , dependenciesTest{} , ...) before Kobalt sees them.
+ |
+
IDocContributor |
+ IContributor |
+ + Plug-ins that know how to generate documentation out of source files should implement this interface. + | +
IInitContributor |
+ IContributor |
+ Kobalt supports the --init command line parameter, which generates a default build file
+ based on the files found in the current directory. Any plug-in that wants to be part of this process need
+ to implement this interface. In this case, both the Java and Kotlin plug-ins define such a contributor
+ but future plug-ins might use this contributor to generate their own build file: Android, Ceylon, Spring, etc...
+ |
+
IProjectContributor |
+ IContributor |
+ Some plug-ins produce projects (Java, Kotlin) while others don't (Packaging, Application, etc...). The ones that + do need to register themselves as project contributors. This is how Kobalt collects all the projects defined + after a build file was parsed. | +
IRepoContributor |
+ IContributor |
+
+ Some plug-ins might want to add their own repository to the list of repositories that Kobalt already supports.
+ This is the case of the Android plug-in which, once the ANDROID_HOME environment variable has been
+ defined, will automatically add the repository inside the Android distribution so that support libraries and other
+ artifacts can be found.
+ |
+
ISourceDirectoryInterceptor |
+ IInterceptor |
+ + Plug-ins that wamt to add, remove or alter the source directories should implement this interface. + | +
IRunnerContributor |
+ IContributor |
+
+ Plug-ins that can operate when the "run" task gets invoked should implement that interface.
+ |
+
ITestRunnerContributor |
+ IContributor |
+
+ Plug-ins that can operate when the "test" task gets invoked should implement that interface.
+ |
+
+ Kobalt itself uses a kobalt-plugin.xml
to define contributors and interceptors, here is
+ an excerpt of it:
+
+<plugin-actors> + <class-name>com.beust.kobalt.plugin.java.JavaPlugin</class-name> + <class-name>com.beust.kobalt.plugin.android.AndroidPlugin</class-name> + + <class-name>com.beust.kobalt.plugin.java.JavaBuildGenerator</class-name> + <class-name>com.beust.kobalt.plugin.kotlin.KotlinBuildGenerator</class-name> +</plugin-actors> ++
+ In order to find out what these actually do, we just need to take a look at their definition and + see which interfaces they implement. For example: +
++class JavaPlugin : ICompilerContributor, IDocContributor {+ +
+ With this declaration, we know that the JavaPlugin
contributes a compiler and a doc generator.
+
+class JavaBuildGenerator: IInitContributor {+
+ This class is declaring that it wants to take part in the --init
selection process, which is
+ discussed in the next section.
+
+ Several plug-ins might want to contribute to a specific task where only one participant only should be allowed, + such as running tests or generating documentation. Even the simple task of compiling should probably only + ever be performed by no more than one plug-in. Therefore, when comes the time to compile a project, + Kobalt needs to find which plug-in is the most suitable for that task and pick it. In order to do that, + plug-ins that contribute to tasks that can only be performed by one candidate need to declare their + affinity to that task for a given project. +
++ Contributors that need to be selected all need to implement the following interface: +
++interface IAffinity { +/** + * @return an integer indicating the affinity of your actor for the given project. The actor that returns + * the highest affinity gets selected. + */ +fun affinity(project: Project, context: KobaltContext) : Int+
+ For example, the JavaPlugin implements the ICompilerContributor
interface and then overrides
+ the affinity
method to make sure it gets run for Java projects but ignored for others:
+
+override fun affinity(project: Project, context: KobaltContext) = + if (project.sourceSuffix == ".java") 1 else 0+
Directives are functions that users of your plug-in can use in their build file in order to configure your plug-in. These can be any kind of Kotlin function but in the interest of preserving a clean syntax in the build file, it's recommended to use the type safe builder pattern, as described here.