diff --git a/plug-in-development/index.html b/plug-in-development/index.html index a54a451..1d502bb 100644 --- a/plug-in-development/index.html +++ b/plug-in-development/index.html @@ -30,54 +30,54 @@ --> -
-- If you are curious to get a quick feel for what a Kobalt plug-in looks like, I suggest you go read how to - write and publish a plug-in in ten minutes and then you can come back here - and keep reading. -
+ ++If you are curious to get a quick feel for what a Kobalt plug-in looks like, I suggest you go read how to +write and publish a plug-in in ten minutes and then you can come back here +and keep reading. +
--
- 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".
-
- 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.
-
+
+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".
+
+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.
+
-
project
or dependencies
. These functions typically configure some data that your plug-in will later use to perform its functions.
- 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:
-
+
project
or dependencies
. These functions typically configure some data that your plug-in will later use to perform its functions.
+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:
+
<plugin-actors> <class-name>com.beust.kobalt.plugin.java.JavaPlugin</class-name> @@ -276,19 +276,19 @@ class JavaBuildGenerator: ITemplateContributor {-
- Several plug-ins might want to contribute to a specific task where only one participant 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 for a given project. 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 want to participate in a selection process need to implement the following interface: -
++Several plug-ins might want to contribute to a specific task where only one participant 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 for a given project. 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 want to participate in a selection process need to implement the following interface: +
interface IProjectAffinity { /** @@ -356,19 +356,19 @@ public fun myConfig(init: Info.() -> Unit) = Info().apply { (Kobalt.findPlugin("my-plug-in") as MyPlugin).info = info this }-
- Obviously, you can choose any kind of API to communicate between the directive and its plug-in. In the code
- above, I chose to directly override the entire Info
field, but you could instead choose to call
- a function, just set one boolean instead of the whole object, etc...
-
- Tasks are provided by plug-ins and can be invoked from the command line, e.g. ./kobaltw assemble
. There are two kinds of tasks: static and dynamic.
-
- Static tasks are functions declared directly in your plug-in class and annotated with the @Task
annotation. Here is an example:
-
+Obviously, you can choose any kind of API to communicate between the directive and its plug-in. In the code
+above, I chose to directly override the entire Info
field, but you could instead choose to call
+a function, just set one boolean instead of the whole object, etc...
+
+Tasks are provided by plug-ins and can be invoked from the command line, e.g. ./kobaltw assemble
. There are two kinds of tasks: static and dynamic.
+
+Static tasks are functions declared directly in your plug-in class and annotated with the @Task
annotation. Here is an example:
+
@Task(name = "lineCount", description = "Count the lines", runBefore = arrayOf("compile")) fun lineCount(project: Project): TaskResult { @@ -376,96 +376,96 @@ fun lineCount(project: Project): TaskResult { return TaskResult() }-
- A Kobalt task needs to accept a Project
in parameter and return a TaskResult
, which indicates whether this task completed successfully.
-
- The @Task
annotation accepts the following attributes:
-
kobaltw
command.
- The difference between runAfter
and alwaysRunAfter
is subtle but important. runAfter
- is just a declaration of dependency. It's basically the reverse of runBefore
but it's useful in case
- you are not the author of the task you want to run before (if you were, you would just use the runBefore
- annotation on it). Since you can't say "a runBefore b"
because you don't own task "a",
- you say "b runAfter a"
.
-
- For example, compileTest
is declared as a runAfter
for the task compile
.
- This means that it doesn't make sense to run compileTest
unless compile
has run first.
- However, if a user invokes the task compile
, they probably don't want to invoke compileTest
,
- so a dependency is exactly what we need here: invoking compileTest
will trigger compile
- but not the other way around.
-
- However, there are times where you want to define a task that will always run after a given task.
- For example, you could have a signJarFile
task that should always be invoked if someone builds a jar
- file. You don't expect users to invoke that target explicitly, but whenever they invoke the assemble
- target, you want your signJarFile
target to be invoked. When you want such a task to always be invoked
- even if the user didn't explicitly request it, you should use alwaysRunAfter
.
- Note that there is no alwaysRunBefore
annotation since runBefore
- achieves the same functionality.
-
- Here are a few different scenarios to illustrate how the three attributes work for the task exampleTask
:
-
- Result of the command ./kobaltw --dryRun compile
-
Configuration for exampleTask |
- Result | - -||||||||||||
runBefore = "compile" | -
+
+A Kobalt task needs to accept a
+The
+The difference between
+For example,
+However, there are times where you want to define a task that will always run after a given task.
+For example, you could have a
+Here are a few different scenarios to illustrate how the three attributes work for the task
+Result of the command
Dynamic tasks-
- Dynamic tasks are useful when you want your plug-in to generate one or several tasks that depend on
- some other runtime information (therefore, you can't declare a method and put a |
+
+Dynamic tasks are useful when you want your plug-in to generate one or several tasks that depend on
+some other runtime information (therefore, you can't declare a method and put a @Task
+annotation on it). Plug-ins declare dynamic tasks by implementing the ITaskContributor
+intrface:
+
interface ITaskContributor { - fun tasksFor(context: KobaltContext) : List<DynamicTask> +fun tasksFor(context: KobaltContext) : List<DynamicTask> }-
- For example: -
++For example: +
override fun tasksFor(context: KobaltContext) = listOf( DynamicTask( @@ -476,15 +476,15 @@ override fun tasksFor(context: KobaltContext) = listOf( println("Running dynamicTask") TaskResult() }))-
- DynamicTask
mirrors the @Task
attributes: name
, description
and
- dependencies. The only addition is the closure
parameter, which specifics the code that will
- run if your task gets invoked. That closure needs to follow the same constraints that a @Task
method
- obeys: it takes a Project
parameter and returns a TaskResult
.
-
- Once you have implemented ITaskContributor
, you can see your dynamic task in the list of tasks and run it directly:
-
+DynamicTask
mirrors the @Task
attributes: name
, description
and
+dependencies. The only addition is the closure
parameter, which specifics the code that will
+run if your task gets invoked. That closure needs to follow the same constraints that a @Task
method
+obeys: it takes a Project
parameter and returns a TaskResult
.
+
+Once you have implemented ITaskContributor
, you can see your dynamic task in the list of tasks and run it directly:
+
$ ./kobaltw --tasks ===== kobalt-line-count ===== @@ -493,32 +493,32 @@ $ ./kobaltw --tasks $ ./kobaltw dynamicTask Running dynamictask-
- Properties are the mechanism that plug-ins can use to export values and also read values that other - plug-ins have exported. There are two kinds of properties that plug-ins can manipulate: -
-
- Project
instances have a property called projectProperties
that is an
- instance of the ProjectProperties
class. Plugins can put and get values on this
- object in order to store project specific properties.
-
+Properties
++Properties are the mechanism that plug-ins can use to export values and also read values that other +plug-ins have exported. There are two kinds of properties that plug-ins can manipulate: +
+
+Project
instances have a property called projectProperties
that is an
+instance of the ProjectProperties
class. Plugins can put and get values on this
+object in order to store project specific properties.
+
fun taskAssemble(project: Project) : TaskResult { - project.projectProperties.put(PACKAGES, packages) +project.projectProperties.put(PACKAGES, packages)-
- The PluginProperties
instance can be found on the KobaltContext
- object that your plug-in receives in its apply()
method. Once you have an instance of this
- class, you can read or write variables into it:
-
+The PluginProperties
instance can be found on the KobaltContext
+object that your plug-in receives in its apply()
method. Once you have an instance of this
+class, you can read or write variables into it:
+
override fun apply(project: Project, context: KobaltContext) { // Export a property for other plug-ins to use @@ -527,33 +527,33 @@ override fun apply(project: Project, context: KobaltContext) { val sourceDir = context.pluginProperties.get("pluginName", "somePluginProperty") }-
- Plug-ins that define properties should annotate them with the @ExportedPluginProperty
or
- @ExportedProjectProperty
annotation:
-
+ Plug-ins that define properties should annotate them with the @ExportedPluginProperty
or
+ @ExportedProjectProperty
annotation:
+
- companion object { - @ExportedProjectProperty - const val BUILD_DIR = "buildDir" +companion object { +@ExportedProjectProperty +const val BUILD_DIR = "buildDir"-