1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt-doc.git synced 2025-04-25 20:07:11 -07:00

Merge branch 'master' of github.com:cbeust/kobalt-doc

This commit is contained in:
Cedric Beust 2016-04-10 21:07:25 -07:00
commit 491722bff7
4 changed files with 320 additions and 246 deletions

View file

@ -527,8 +527,8 @@ Here are the options that you can pass to <code>./kobaltw</code>:
<table style="font-size: 14px" class="table table-striped"> <table style="font-size: 14px" class="table table-striped">
<colgroup> <colgroup>
<col span="1" style="width: 25%;"> <col span="1" style="width: 30%;">
<col span="1" style="width: 10%;"> <col span="1" style="width: 5%;">
<col span="1" style="width: 10%;"> <col span="1" style="width: 10%;">
<col span="1" style="width: 20%;"> <col span="1" style="width: 20%;">
<col span="1" style="width: 40%;"> <col span="1" style="width: 40%;">
@ -551,9 +551,9 @@ Here are the options that you can pass to <code>./kobaltw</code>:
<td>Use this option if you are trying to build a project whose <code>Build.kt</code> is not in <code>kobalt/src</code>.</td> <td>Use this option if you are trying to build a project whose <code>Build.kt</code> is not in <code>kobalt/src</code>.</td>
</tr> </tr>
<tr> <tr>
<td><code>--checkVersions</code></td> <td><code><span style="white-space:nowrap">--checkVersions</span></code></td>
<td>Boolean</td> <td>Boolean</td>
<td>false</td>td> <td>false</td>
<td>Display all the new versions of your dependencies.</td> <td>Display all the new versions of your dependencies.</td>
<td>This option looks at all the dependencies found in your build file and then contacts all the Maven repositories in order to find out if any of these repos contains a newer version. If any are found, they are displayed: <td>This option looks at all the dependencies found in your build file and then contacts all the Maven repositories in order to find out if any of these repos contains a newer version. If any are found, they are displayed:
<pre class="brush:plain"> <pre class="brush:plain">
@ -579,7 +579,7 @@ New versions found:
<td>The parameter to this argument is a list of template names separated by commas, e.g. <code>"java,myProject"</code>. Each template will be invoked in order so they can generate their files.</td> <td>The parameter to this argument is a list of template names separated by commas, e.g. <code>"java,myProject"</code>. Each template will be invoked in order so they can generate their files.</td>
</tr> </tr>
<tr> <tr>
<td><code>--listTemplates</code></td> <td><code><span style="white-space:nowrap">--listTemplates</span></code></td>
<td></td> <td></td>
<td>N/A</td> <td>N/A</td>
<td>List all the templates available.</td> <td>List all the templates available.</td>
@ -592,6 +592,14 @@ New versions found:
<td>Specify the log level.</td> <td>Specify the log level.</td>
<td>The default level is 1. Level 0 will quiet everything and 2 and 3 will display increasingly verbose output.</td> <td>The default level is 1. Level 0 will quiet everything and 2 and 3 will display increasingly verbose output.</td>
</tr> </tr>
<tr>
<td><code><span style="white-space:nowrap">--noIncremental</span></code></td>
<td>Boolean</td>
<td>false</td>
<td>Turn off incremental builds.</td>
<td>If this flag is specified, Kobalt will run all the tasks, even those that are incremental and would have
been skipped.</td>
</tr>
<tr> <tr>
<td><code>--plugins</code></td> <td><code>--plugins</code></td>
<td>Comma-separated list of plugin id's</td> <td>Comma-separated list of plugin id's</td>
@ -600,7 +608,7 @@ New versions found:
<td>This is similar to specifying these plug-in id's in a build file except that no build file is needed.</td> <td>This is similar to specifying these plug-in id's in a build file except that no build file is needed.</td>
</tr> </tr>
<tr> <tr>
<td><code>--pluginJarFiles</code></td> <td><code><span style="white-space:nowrap">--pluginJarFiles</span></code></td>
<td>Comma-separated list of plugin jar files</td> <td>Comma-separated list of plugin jar files</td>
<td></td> <td></td>
<td>Specify the plug-ins to load.</td> <td>Specify the plug-ins to load.</td>
@ -613,27 +621,20 @@ New versions found:
<td>Display information about the given id.</td> <td>Display information about the given id.</td>
<td>Display which repo this artifact can be found in and the whole graph of its dependencies.</td> <td>Display which repo this artifact can be found in and the whole graph of its dependencies.</td>
</tr> </tr>
<tr> <tr>
<td><code>--resolve</code></td> <td><code>--tasks</code></td>
<td>Maven id<br/>(e.g.&nbsp;<code>"com.beust:kobalt:0.228"</code>)</td> <td>Boolean</td>
<td>N/A</td> <td>false</td>
<td>Display information about the given id.</td> <td>List the tasks available.</td>
<td>Display which repo this artifact can be found in and the whole graph of its dependencies.</td> <td>Note that the available tasks will vary depending on which projects are in your build file.</td>
</tr> </tr>
<tr> <tr>
<td><code>--tasks</code></td> <td><code>--update</code></td>
<td>Boolean</td> <td>Boolean</td>
<td>false</td> <td>false</td>
<td>List the tasks available.</td> <td>Update Kobalt to the latest version available.</td>
<td>Note that the available tasks will vary depending on which projects are in your build file.</td> <td>Use this flag if Kobalt just notified you that a new version is available and you want to update. Another way of doing this is to edit <code>kobalt/wrapper/kobalt-wrapper.properties</code> manually.</td>
</tr> </tr>
<tr>
<td><code>--update</code></td>
<td>Boolean</td>
<td>false</td>
<td>Update Kobalt to the latest version available.</td>
<td>Use this flag if Kobalt just notified you that a new version is available and you want to update. Another way of doing this is to edit <code>kobalt/wrapper/kobalt-wrapper.properties</code> manually.</td>
</tr>
</table> </table>
<h2 class="section" id="testing">Testing</h2> <h2 class="section" id="testing">Testing</h2>

View file

@ -51,13 +51,13 @@ $ which kobaltw
</p> </p>
<h3 class="section" indent="1" id="manually">Manually</h3> <h3 class="section" indent="1" id="manually">Manually</h3>
<p> <p>
<a href="https://github.com/cbeust/kobalt/releases/latest">Download the zip file</a>, unzip it and add that directory to your <code>$PATH</code> variable so that you can invoke the command <code>kobaltw</code>. <a href="https://github.com/cbeust/kobalt/releases/latest">Download the zip file</a>, unzip it and add the <code>bin</code> directory to your <code>$PATH</code> variable so that you can invoke the command <code>kobaltw</code>:
</p> </p>
<pre class="brush:plain"> <pre class="brush:plain">
cd yourLocation cd yourLocation
unzip kobalt-xxx.zip unzip kobalt-xxx.zip
cd kobalt-xxx cd kobalt-xxx
export PATH=$PWD:$PATH export PATH=$PWD/bin:$PATH
</pre> </pre>
<h2 class="section" id="initialize">2. Initialize your project</h2> <h2 class="section" id="initialize">2. Initialize your project</h2>
<p> <p>
@ -129,7 +129,7 @@ val jcommander = project {
</p> </p>
<pre class="brush:java"> <pre class="brush:java">
./kobaltw assemble</pre> ./kobaltw assemble</pre>
<h2 class="section" id="idea-plugin">5. IDEA users: generate IDEA files</h2> <h2 class="section" id="generate-idea-files">5. IDEA users: generate IDEA files</h2>
<p> <p>
If you are planning to use IDEA to work on your project, you can ask Kobalt to generate all the IDEA files necessary to import your project: If you are planning to use IDEA to work on your project, you can ask Kobalt to generate all the IDEA files necessary to import your project:
</p> </p>
@ -147,7 +147,8 @@ If you are planning to use IDEA to work on your project, you can ask Kobalt to g
</p> </p>
<h2 class="section" id="idea-plugin">6. IDEA users: sync your build file</h2> <h2 class="section" id="idea-plugin">6. IDEA users: sync your build file</h2>
<p> <p>
If you're using Intellij IDEA, make sure you've <a href="../idea-plug-in/index.html">installed the Kobalt plugin</a> and then go to <code>Kobalt -> Sync Build File</code>. Once the build file is synchronized, the errors should disappear If you're using Intellij IDEA, make sure you've <a href="../idea-plug-in/index.html">installed the Kobalt plugin</a> and then go to <code>Tools &rarr; Kobalt &rarr; Sync Build File</code>. Once the build file is synchronized, the errors should
disappear
and you can now use all the regular functions of IDEA on <code>Build.kt</code> just like any other Kotlin and you can now use all the regular functions of IDEA on <code>Build.kt</code> just like any other Kotlin
files (auto completion, jump to symbol, etc...). files (auto completion, jump to symbol, etc...).
</p> </p>

View file

@ -72,7 +72,7 @@
<img src="../pics/install-plugin.png" class="img-rounded kb-wide"/> <img src="../pics/install-plugin.png" class="img-rounded kb-wide"/>
</p> </p>
<p> <p>
Install it and restart IDEA. If the plug-in was correctly installed, you should see a new menu called "Kobalt" juste before the "Help" menu: Install it and restart IDEA. If the plug-in was correctly installed, you should see a new menu called "Kobalt" in the "Tools" menu:
</p> </p>
<p align="center"> <p align="center">
<img src="../pics/kobalt-menu.png" class="img-rounded"/> <img src="../pics/kobalt-menu.png" class="img-rounded"/>

View file

@ -30,54 +30,120 @@
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
--> -->
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<!-- Static navbar --> <!-- Static navbar -->
<nav id="kobalt-navbar" class="navbar navbar-default"> <nav id="kobalt-navbar" class="navbar navbar-default">
</nav> </nav>
<!-- Main component for a primary marketing message or call to action --> <!-- Main component for a primary marketing message or call to action -->
<h2>How to write a Kobalt plug-in</h2> <h2>How to write a Kobalt plug-in</h2>
<!-- Main content --> <!-- Main content -->
<div class="col-md-9"> <div class="col-md-9">
<h2 class="section" id="tutorial">Tutorial</h2> <h2 class="section" id="tutorial">Tutorial</h2>
<p> <p>
If you are curious to get a quick feel for what a Kobalt plug-in looks like, I suggest you go read how to If you are curious to get a quick feel for what a Kobalt plug-in looks like, I suggest you go read how to
<a href="../ten-minutes/index.html">write and publish a plug-in in ten minutes</a> and then you can come back here <a href="../ten-minutes/index.html">write and publish a plug-in in ten minutes</a> and then you can come back here
and keep reading. and keep reading.
</p> </p>
<h2 class="section" id="idea-set-up">Setting up IDEA</h2>
<h3 class="section" indent="1" id="launch-configuration">Launch configuration</h3>
<p>
The simplest way to run your plug-in in your IDE is to create a main function in the main class of your
plug-in as follows:
</p>
<pre class="brush:java">
fun main(argv: Array&lt;String&gt;) {
com.beust.kobalt.main(argv)
}
</pre>
<p>
In order for this code to compile, you will have to switch the dependency of your plug-in from
<code>kobalt-plugin-api</code> to just <code>kobalt</code>, which is the actual application (and which
therefore contains the <code>main()</code> entry point).
</p>
<pre class="brush:java">
// Normal dependency
compile("com.beust:kobalt-plugin-api:$KOBALT_VERSION")
<h2 class="section" id="philosophy">Plug-in architecture</h3> // Development dependency
<p> compile("com.beust:kobalt:$KOBALT_VERSION")
<p> </pre>
Plug-ins often produce files and data that other plug-ins need to use in order for a build to succeed. For example, <p>
the Android plug-in needs to generate a file called <code>R.java</code> and then make this file available at You might find it convenient to leverage Kobalt's ability to use regular Kotlin variables to make things easier:
compile time by the Java or Kotlin (or any other language) plug-in. Since plug-ins have no idea about what other </p>
plug-ins are currently enabled and running, they can't directly talk to each other so instead of calling into <pre class="brush:java">
Kobalt, Kobalt calls into them. This is done by declaring various "actors" that Kobalt will invoke whenever val dev = false
it needs the information that your plug-in produced. This is a design pattern often referred to as the val kobaltDependency = if (dev) "kobalt" else "kobalt-plugin-api"
<a href="https://en.wikipedia.org/wiki/Hollywood_principle">"Hollywood Principle"</a>: "Don't call us, we'll call you".
</p>
<p>
These "actors" are exactly what the <code>kobalt-plugin.xml</code> 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.
</p>
</p>
<h3 class="section" id="introduction" indent="1">Parts</h2> val p = project {
<p> // ...
<ul>
<li><a href="#plugin-xml"><b>kobalt-plugin.xml</b></a>. A file that describes all the components (called "plug-in actors") of your plug-in, such as contributors.</li> compile("com.beust:$kobaltDependency:$KOBALT_VERSION")
<li><a href="#directives"><b>Directives</b></a>. Kotlin functions that users of your plug-in can invoke in their build file, such as <code>project</code> or <code>dependencies</code>. These functions typically configure some data that your plug-in will later use to perform its functions.</li> }
<li><a href="#tasks"><b>Tasks</b></a>. These tasks are invoked from the command line and ask your plug-ins to perform certain actions.</li> </pre>
<li><a href="#properties"><b>Properties</b></a>. Plug-ins can export properties and read properties from other plug-ins.</li> <p>
</ul> Then you can simply set the <code>dev</code> to <code>true</code> during development and back to <code>false
</p> </code> when you are ready to publish your plug-in.
</code>
<h3 class="section" id="kobalt-plugin-xml" indent="1">kobalt-plugin.xml</h2> </p>
<p> <p>
The <code>kobalt-plugin.xml</code> file (stored in <code>META-INF</code> 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 <code>IPluginActor</code>'s interfaces: Then resync your build file in IDEA and your <code>main()</code> function should now build and be launchable.
</p> You can right click on that class file and select "Debug &lt;your class name&gt;", which will launch Kobalt
with your plug-in. You can set a breakpoint in one of your tasks or anywhere that gets invoked. Don't forget
to invoke this launch configuration with the regular parameters passed to Kobalt (e.g. <code>"assemble"</code>).
</p>
<h3 class="section" indent="1" id="local-dependencies">Local dependencies</h3>
<p>
In the process of building your plug-in, you will probably be invoking it from test projects and since
you will be making changes to your plug-in and generating jar files often, you might find it more convenient
to have these test projects point to your local jar file instead of the Maven one (which would require you
to upload your plug-in all the time). For this, you might find the <code>file()</code> and <code>homeDir
()</code> directives convenient:
</p>
<pre class="brush:java">
// Regular dependency
compile("com.example:myPlugin:0.1")
// Development dependency
compile(file(homeDir("kotlin/myPlugin/kobaltBuild/libs/myPlugin-0.1.jar"))
</pre>
<p>
With this latter configuration, simply build your plug-in to generate the jar file with <code>./kobaltw
assemble</code>, switch to your test project and invoke Kobalt on it so that your plug-in will get invoked
and you should see the latest version of your code being invoked.
</p>
<h2 class="section" id="philosophy">Plug-in architecture</h3>
<p>
<p>
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 <code>R.java</code> 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
<a href="https://en.wikipedia.org/wiki/Hollywood_principle">"Hollywood Principle"</a>: "Don't call us, we'll call you".
</p>
<p>
These "actors" are exactly what the <code>kobalt-plugin.xml</code> 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.
</p>
</p>
<h3 class="section" id="introduction" indent="1">Parts</h2>
<p>
<ul>
<li><a href="#plugin-xml"><b>kobalt-plugin.xml</b></a>. A file that describes all the components (called "plug-in actors") of your plug-in, such as contributors.</li>
<li><a href="#directives"><b>Directives</b></a>. Kotlin functions that users of your plug-in can invoke in their build file, such as <code>project</code> or <code>dependencies</code>. These functions typically configure some data that your plug-in will later use to perform its functions.</li>
<li><a href="#tasks"><b>Tasks</b></a>. These tasks are invoked from the command line and ask your plug-ins to perform certain actions.</li>
<li><a href="#properties"><b>Properties</b></a>. Plug-ins can export properties and read properties from other plug-ins.</li>
</ul>
</p>
<h3 class="section" id="kobalt-plugin-xml" indent="1">kobalt-plugin.xml</h2>
<p>
The <code>kobalt-plugin.xml</code> file (stored in <code>META-INF</code> 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 <code>IPluginActor</code>'s interfaces:
</p>
<pre class="brush:xml"> <pre class="brush:xml">
&lt;plugin-actors&gt; &lt;plugin-actors&gt;
&lt;class-name&gt;com.beust.kobalt.plugin.java.JavaPlugin&lt;/class-name&gt; &lt;class-name&gt;com.beust.kobalt.plugin.java.JavaPlugin&lt;/class-name&gt;
@ -276,19 +342,19 @@ class JavaBuildGenerator: ITemplateContributor {</pre>
</td> </td>
</tr> </tr>
</table> </table>
<h2 class="section" id="selection-process">Selection process</h2> <h2 class="section" id="selection-process">Selection process</h2>
<p> <p>
Several plug-ins might want to contribute to a specific task where only one participant should be allowed, 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 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 ever be performed by no more than one plug-in for a given project. Therefore, when comes the time to
compile a project, 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, 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 plug-ins that contribute to tasks that can only be performed by one candidate need to declare their
<em>affinity</em> to that task for a given project. <em>affinity</em> to that task for a given project.
</p> </p>
<p> <p>
Contributors that want to participate in a selection process need to implement the following interface: Contributors that want to participate in a selection process need to implement the following interface:
</p> </p>
<pre class="brush:java"> <pre class="brush:java">
interface IProjectAffinity { interface IProjectAffinity {
/** /**
@ -356,19 +422,19 @@ public fun myConfig(init: Info.() -> Unit) = Info().apply {
(Kobalt.findPlugin("my-plug-in") as MyPlugin).info = info (Kobalt.findPlugin("my-plug-in") as MyPlugin).info = info
this this
}</pre> }</pre>
<p> <p>
Obviously, you can choose any kind of API to communicate between the directive and its plug-in. In the code 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 <code>Info</code> field, but you could instead choose to call above, I chose to directly override the entire <code>Info</code> field, but you could instead choose to call
a function, just set one boolean instead of the whole object, etc... a function, just set one boolean instead of the whole object, etc...
</p> </p>
<h2 class="section" id="tasks">Tasks</h2> <h2 class="section" id="tasks">Tasks</h2>
<p> <p>
Tasks are provided by plug-ins and can be invoked from the command line, e.g. <code>./kobaltw assemble</code>. There are two kinds of tasks: static and dynamic. Tasks are provided by plug-ins and can be invoked from the command line, e.g. <code>./kobaltw assemble</code>. There are two kinds of tasks: static and dynamic.
</p> </p>
<h3 class="section" indent="1">Static tasks</h3> <h3 class="section" indent="1">Static tasks</h3>
<p> <p>
Static tasks are functions declared directly in your plug-in class and annotated with the <code>@Task</code> annotation. Here is an example: Static tasks are functions declared directly in your plug-in class and annotated with the <code>@Task</code> annotation. Here is an example:
</p> </p>
<pre class="brush:java"> <pre class="brush:java">
@Task(name = "lineCount", description = "Count the lines", runBefore = arrayOf("compile")) @Task(name = "lineCount", description = "Count the lines", runBefore = arrayOf("compile"))
fun lineCount(project: Project): TaskResult { fun lineCount(project: Project): TaskResult {
@ -376,96 +442,96 @@ fun lineCount(project: Project): TaskResult {
return TaskResult() return TaskResult()
} }
</pre> </pre>
<p> <p>
A Kobalt task needs to accept a <code>Project</code> in parameter and return a <code>TaskResult</code>, which indicates whether this task completed successfully. A Kobalt task needs to accept a <code>Project</code> in parameter and return a <code>TaskResult</code>, which indicates whether this task completed successfully.
</p> </p>
<p> <p>
The <code>@Task</code> annotation accepts the following attributes: The <code>@Task</code> annotation accepts the following attributes:
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt>name</dt> <dt>name</dt>
<dd>The name of the task, which will be used to invoke it from the command line.</dd> <dd>The name of the task, which will be used to invoke it from the command line.</dd>
<dt>description</dt> <dt>description</dt>
<dd>The description of this command, which will be displayed if the user invokes the usage for the <code>kobaltw</code> command.</dd> <dd>The description of this command, which will be displayed if the user invokes the usage for the <code>kobaltw</code> command.</dd>
<dt>runBefore</dt> <dt>runBefore</dt>
<dd>A list of all the tasks that this task should run prior to.</dd> <dd>A list of all the tasks that this task should run prior to.</dd>
<dt>runAfter</dt> <dt>runAfter</dt>
<dd>A list of all the tasks that should run before this task does.</dd> <dd>A list of all the tasks that should run before this task does.</dd>
<dt>alwaysRunAfter</dt> <dt>alwaysRunAfter</dt>
<dd>A list of all the tasks that will always be run after this task if it's invoked.</dd> <dd>A list of all the tasks that will always be run after this task if it's invoked.</dd>
</dl> </dl>
</p> </p>
<p> <p>
The difference between <code>runAfter</code> and <code>alwaysRunAfter</code> is subtle but important. <code>runAfter</code> The difference between <code>runAfter</code> and <code>alwaysRunAfter</code> is subtle but important. <code>runAfter</code>
is just a declaration of dependency. It's basically the reverse of <code>runBefore</code> but it's useful in case is just a declaration of dependency. It's basically the reverse of <code>runBefore</code> 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 <code>runBefore</code> you are not the author of the task you want to run before (if you were, you would just use the <code>runBefore</code>
annotation on it). Since you can't say <code>"a runBefore b"</code> because you don't own task "a", annotation on it). Since you can't say <code>"a runBefore b"</code> because you don't own task "a",
you say <code>"b runAfter a"</code>. you say <code>"b runAfter a"</code>.
</p> </p>
<p> <p>
For example, <code>compileTest</code> is declared as a <code>runAfter</code> for the task <code>compile</code>. For example, <code>compileTest</code> is declared as a <code>runAfter</code> for the task <code>compile</code>.
This means that it doesn't make sense to run <code>compileTest</code> unless <code>compile</code> has run first. This means that it doesn't make sense to run <code>compileTest</code> unless <code>compile</code> has run first.
However, if a user invokes the task <code>compile</code>, they probably don't want to invoke <code>compileTest</code>, However, if a user invokes the task <code>compile</code>, they probably don't want to invoke <code>compileTest</code>,
so a dependency is exactly what we need here: invoking <code>compileTest</code> will trigger <code>compile</code> so a dependency is exactly what we need here: invoking <code>compileTest</code> will trigger <code>compile</code>
but not the other way around. but not the other way around.
</p> </p>
<p> <p>
However, there are times where you want to define a task that will <strong>always</strong> run after a given task. However, there are times where you want to define a task that will <strong>always</strong> run after a given task.
For example, you could have a <code>signJarFile</code> task that should always be invoked if someone builds a jar For example, you could have a <code>signJarFile</code> 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 <code>assemble</code> file. You don't expect users to invoke that target explicitly, but whenever they invoke the <code>assemble</code>
target, you want your <code>signJarFile</code> target to be invoked. When you want such a task to always be invoked target, you want your <code>signJarFile</code> 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 <code>alwaysRunAfter</code>. even if the user didn't explicitly request it, you should use <code>alwaysRunAfter</code>.
Note that there is no <code>alwaysRunBefore</code> annotation since <code>runBefore</code> Note that there is no <code>alwaysRunBefore</code> annotation since <code>runBefore</code>
achieves the same functionality. achieves the same functionality.
</p> </p>
<p> <p>
Here are a few different scenarios to illustrate how the three attributes work for the task <code>exampleTask</code>: Here are a few different scenarios to illustrate how the three attributes work for the task <code>exampleTask</code>:
</p> </p>
<p align="center"> <p align="center">
<strong>Result of the command <code>./kobaltw --dryRun compile</code></strong> <strong>Result of the command <code>./kobaltw --dryRun compile</code></strong>
</p> </p>
<table width="100%" class="table table-bordered table-condensed"> <table width="100%" class="table table-bordered table-condensed">
<thead> <thead>
<td align="center">Configuration for <code>exampleTask</code></td> <td align="center">Configuration for <code>exampleTask</code></td>
<td align="center">Result</td> <td align="center">Result</td>
</thead> </thead>
<tr> <tr>
<td align="center">runBefore = "compile"</td> <td align="center">runBefore = "compile"</td>
<td> <td>
<pre class="brush:plain">kobalt-line-count:clean <pre class="brush:plain">kobalt-line-count:clean
kobalt-line-count:exampleTask kobalt-line-count:exampleTask
kobalt-line-count:compile</pre> kobalt-line-count:compile</pre>
</td> </td>
</tr> </tr>
<tr> <tr>
<td align="center">runAfter = "compile"</td> <td align="center">runAfter = "compile"</td>
<td> <td>
<pre class="brush:plain">kobalt-line-count:clean <pre class="brush:plain">kobalt-line-count:clean
kobalt-line-count:compile</pre> kobalt-line-count:compile</pre>
</td> </td>
</tr> </tr>
<tr> <tr>
<td align="center">alwaysRunAfter = "compile"</td> <td align="center">alwaysRunAfter = "compile"</td>
<td> <td>
<pre class="brush:plain">kobalt-line-count:clean <pre class="brush:plain">kobalt-line-count:clean
kobalt-line-count:compile kobalt-line-count:compile
kobalt-line-count:exampleTask</pre> kobalt-line-count:exampleTask</pre>
</td> </td>
</tr> </tr>
</table> </table>
<h3 class="section" indent="1">Dynamic tasks</h3> <h3 class="section" indent="1">Dynamic tasks</h3>
<p> <p>
Dynamic tasks are useful when you want your plug-in to generate one or several tasks that depend on 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 <code>@Task</code> some other runtime information (therefore, you can't declare a method and put a <code>@Task</code>
annotation on it). Plug-ins declare dynamic tasks by implementing the <code>ITaskContributor</code> annotation on it). Plug-ins declare dynamic tasks by implementing the <code>ITaskContributor</code>
intrface: intrface:
</p> </p>
<pre class="brush:java"> <pre class="brush:java">
interface ITaskContributor { interface ITaskContributor {
fun tasksFor(context: KobaltContext) : List&lt;DynamicTask&gt; fun tasksFor(context: KobaltContext) : List&lt;DynamicTask&gt;
}</pre> }</pre>
<p> <p>
For example: For example:
</p> </p>
<pre class="brush:java"> <pre class="brush:java">
override fun tasksFor(context: KobaltContext) = listOf( override fun tasksFor(context: KobaltContext) = listOf(
DynamicTask( DynamicTask(
@ -476,15 +542,15 @@ override fun tasksFor(context: KobaltContext) = listOf(
println("Running dynamicTask") println("Running dynamicTask")
TaskResult() TaskResult()
}))</pre> }))</pre>
<p> <p>
<code>DynamicTask</code> mirrors the <code>@Task</code> attributes: <code>name</code>, <code>description</code> and <code>DynamicTask</code> mirrors the <code>@Task</code> attributes: <code>name</code>, <code>description</code> and
dependencies. The only addition is the <code>closure</code> parameter, which specifics the code that will dependencies. The only addition is the <code>closure</code> parameter, which specifics the code that will
run if your task gets invoked. That closure needs to follow the same constraints that a <code>@Task</code> method run if your task gets invoked. That closure needs to follow the same constraints that a <code>@Task</code> method
obeys: it takes a <code>Project</code> parameter and returns a <code>TaskResult</code>. obeys: it takes a <code>Project</code> parameter and returns a <code>TaskResult</code>.
</p> </p>
<p> <p>
Once you have implemented <code>ITaskContributor</code>, you can see your dynamic task in the list of tasks and run it directly: Once you have implemented <code>ITaskContributor</code>, you can see your dynamic task in the list of tasks and run it directly:
</p> </p>
<pre class="brush:plain"> <pre class="brush:plain">
$ ./kobaltw --tasks $ ./kobaltw --tasks
===== kobalt-line-count ===== ===== kobalt-line-count =====
@ -493,32 +559,38 @@ $ ./kobaltw --tasks
$ ./kobaltw dynamicTask $ ./kobaltw dynamicTask
Running dynamictask Running dynamictask
</pre> </pre>
<h2 class="section" id="properties">Properties</h2> <h2 class="section" id="properties">Properties</h2>
<p> <p>
Properties are the mechanism that plug-ins can use to export values and also read values that other 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: plug-ins have exported. There are two kinds of properties that plug-ins can manipulate:
</p> </p>
<ul> <ul>
<li><strong>Project properties</strong>: project-specific properties.</li> <li><strong>Project properties</strong>: project-specific properties.</li>
<li><strong>Plug-in properties</strong>: general properties that are applicable to no project <li><strong>Plug-in properties</strong>: general properties that are applicable to no project
in particular.</li> in particular.</li>
</ul> </ul>
<h3 class="section" indent="1" id="project-properties">Project properties</h3> <h3 class="section" indent="1" id="project-properties">Project properties</h3>
<p> <p>
<code>Project</code> instances have a property called <code>projectProperties</code> that is an <code>Project</code> instances have a property called <code>projectProperties</code> that is an
instance of the <code>ProjectProperties</code> class. Plugins can put and get values on this instance of the <code>ProjectProperties</code> class. Plugins can put and get values on this
object in order to store project specific properties. object in order to store project specific properties.
</p> </p>
<pre class="brush:java"> <pre class="brush:java">
fun taskAssemble(project: Project) : TaskResult { fun taskAssemble(project: Project) : TaskResult {
project.projectProperties.put(PACKAGES, packages) project.projectProperties.put("packages", packages)
</pre> </pre>
<h3 class="section" indent="1" id="plugin-properties">Plug-in properties</h3> <p>
<p> Another plug-in can then query this property as follows:
The <code>PluginProperties</code> instance can be found on the <code>KobaltContext</code> </p>
object that your plug-in receives in its <code>apply()</code> method. Once you have an instance of this <pre class="brush:java">
class, you can read or write variables into it: val packages = project.projectProperties.put("packages")
</p> </pre>
<h3 class="section" indent="1" id="plugin-properties">Plug-in properties</h3>
<p>
The <code>PluginProperties</code> instance can be found on the <code>KobaltContext</code>
object that your plug-in receives in its <code>apply()</code> method. Once you have an instance of this
class, you can read or write variables into it:
</p>
<pre class="brush:java"> <pre class="brush:java">
override fun apply(project: Project, context: KobaltContext) { override fun apply(project: Project, context: KobaltContext) {
// Export a property for other plug-ins to use // Export a property for other plug-ins to use
@ -527,33 +599,33 @@ override fun apply(project: Project, context: KobaltContext) {
val sourceDir = context.pluginProperties.get("pluginName", "somePluginProperty") val sourceDir = context.pluginProperties.get("pluginName", "somePluginProperty")
} }
</pre> </pre>
<h3 class="section" indent="1" id="documenting-properties">Documenting properties</h3> <h3 class="section" indent="1" id="documenting-properties">Documenting properties</h3>
<p> <p>
Plug-ins that define properties should annotate them with the <code>@ExportedPluginProperty</code> or Plug-ins that define properties should annotate them with the <code>@ExportedPluginProperty</code> or
<code>@ExportedProjectProperty</code>annotation: <code>@ExportedProjectProperty</code>annotation:
</p> </p>
<pre class="brush:java"> <pre class="brush:java">
companion object { companion object {
@ExportedProjectProperty @ExportedProjectProperty
const val BUILD_DIR = "buildDir" const val BUILD_DIR = "buildDir"
</pre> </pre>
</div> </div>
<!-- Table of contents --> <!-- Table of contents -->
<div class="col-md-3" id="table-of-contents"> <div class="col-md-3" id="table-of-contents">
</div> </div>
<!-- Bootstrap core JavaScript <!-- Bootstrap core JavaScript
================================================== --> ================================================== -->
<!-- Placed at the end of the document so the pages load faster --> <!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="../bootstrap/dist/js/bootstrap.min.js"></script> <script src="../bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../js/kobalt.js"></script> <script src="../js/kobalt.js"></script>
<script>generateKobalt();</script> <script>generateKobalt();</script>
<!-- <!--
<script src="../bootstrap/dist/js/docs.min.js"></script> <script src="../bootstrap/dist/js/docs.min.js"></script>
--> -->
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<!-- <!--
<script src="../../assets/js/ie10-viewport-bug-workaround.js"></script> <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
--> -->
</div> </div>
</body> </body>