diff --git a/documentation/index.html b/documentation/index.html index 398300e..d1bcb43 100644 --- a/documentation/index.html +++ b/documentation/index.html @@ -57,9 +57,7 @@
-

Kobalt

-

A universal build system for the exigent developer.

- +

Documentation

+ + + + + + + + + + + + + + +
+ + + + + +
+

Kobalt

+

A universal build system for the exigent developer.

+ + + +
+ + +
+ +

1. Download Kobalt

+ +

+Download the zip file then unzip it in a location we'll call KOBALT_HOME: +

+ +
+cd $KOBALT_HOME
+unzip kobalt-xxx.zip
+
+ +

2. Initialize your project for Kobalt

+ +

+Change to your project directory and call the kobaltw command with --init: +

+ +
+cd ~/java/project
+$KOBALT_HOME/kobaltw --init
+
+ +

+This command will do two things: +

+ +
    +
  1. Create a default kobalt/src/Build.kt file based on what was found there. +
  2. Install the Kobalt Wrapper in your current directory (script `kobaltw`) and in the kobalt/ directory. From now on, you can just use ./kobaltw to build and you can ignore $KOBALT_HOME. +
+ +

+You can now attempt to build your project with Kobalt: +

+ +
+./kobaltw assemble
+
+ +If your project follows a regular build structure (e.g. Maven's hierarchy), this should compile your file and create a .jar file. If not, you will have to make a few edits to your Build.kt. + +As of this writing, Kobalt supports Java and Kotlin projects. + +

3. Edit Build.kt

+ +
+import com.beust.kobalt.*
+import com.beust.kobalt.plugin.kotlin.kotlinProject
+
+val kobalt = kotlinProject {
+    name = "kobalt"
+    group = "com.beust"
+    artifactId = name
+    version = "0.62"
+    directory = homeDir("kotlin/kobalt")
+}
+
+ +
+ + + +
+
+
+ + + + + + + + + + + + + diff --git a/home/index.html b/home/index.html index dc8a716..3a3f24d 100644 --- a/home/index.html +++ b/home/index.html @@ -55,14 +55,20 @@
-

What is Kobalt?

+

Kobalt: friendly, fast build system

+
-

Overview

-Kobalt is a build system system featuring build files written in Kotlin. It's focused on offering an intuitive DSL and plug-in architecture, fast builds and build file auto completion from your favorite IDE. +

Features

+

@@ -123,10 +129,6 @@ Kobalt is currently in Beta but I'm already using it to build most of my project

  • ... and of course, Kobalt itself (this build file demonstrates multi projects and project dependencies).
  • -

    - Where to next? Are you interested in writing some cool Kotlin code and contribute to Kobalt? Or maybe just download and run Kobalt on your own projects just to get a feel for it? Then proceed to Kobalt's main documentation! -

    -

    @@ -142,7 +144,7 @@ Kobalt is currently in Beta but I'm already using it to build most of my project - + + + + + + + + + + +
    + + + +
    +

    Plug-in development

    +

    How to write a Kobalt plug-in.

    +
    + +
    +

    Tutorial

    +

    + 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-in architecture

    +

    +

    + 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-in development

    -

    How to write a Kobalt plug-in.

    -
    - - -
    - -

    Introduction

    - -

    - Kobalt plug-ins are usually made of several parts: - -

      -
    • kobalt-plugin.xml. A file that describes all the components (called "plug-in actors") of your plug-in, such as contributors.
    • -
    • Directives. Kotlin functions that users of your plug-in can invoke in their build file, such as kotlinProject or dependencies. These functions typically configure some data that your plug-in will later use to perform its functions.
    • -
    • Tasks. These tasks are invoked from the command line and ask your plug-ins to perform certain actions.
    • -
    • Properties. Plug-ins can export properties and read properties from other plug-ins.
    • -
    -

    -

    - 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. -

    - -

    kobalt-plugin.xml

    -

    - 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>
    -    <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: -

    -
      -
    • Plugins, which contain @Task annotations.
    • -
    • Interceptors, which transform data that Kobalt gives them.
    • -
    • Contributors, which produce additional data.
    • -
    -

    - 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. - -

    - -

    Plug-in architecture philosophy

    -

    -

    - 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. - -

    -

    - -

    List of plug-in actors

    -

    - Here is a list of actors (contributors and interceptors) that you can define in your plug-in. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Interface nameTypeDescription
    - IBuildConfigFieldContributorIInterceptor - Plug-ins that want to add custom fields to the generated BuildConfig class. -
    IBuildDirectoryInterceptorIInterceptor - 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. -
    ICompilerContributorIContributor - Plug-ins that know how to turn files into bytecodes should implement this interface. -
    ICompilerFlagContributorIContributor - - Plug-ins that need to add flags to the compiler. -
    ICompilerInterceptorIInterceptor - Plug-ins that implement this interface get a chance to alter the dependencies of a project (dependencies{}, dependenciesTest{}, ...) before Kobalt sees them. -
    IDocContributorIContributor - Plug-ins that know how to generate documentation out of source files should implement this interface. -
    IInitContributorIContributor 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... -
    IProjectContributorIContributor 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.
    IRepoContributorIContributor - 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. -
    IRunnerContributorIContributor - Plug-ins that can operate when the "run" task gets invoked should implement that interface. -
    - ISourceDirectoryContributorIContributor - - Plug-ins that add source directories. -
    - ISourceDirectoryInterceptorIInterceptor - Plug-ins that want to add, remove or alter the source directories should implement this interface. -
    - ITestRunnerContributorIContributor - Plug-ins that can operate when the "test" task gets invoked should implement that interface. -
    - ITestSourceDirectoryContributorIContributor - - Plug-ins that add test source directories. -
    - -

    Example

    -

    - Kobalt itself uses a kobalt-plugin.xml to define contributors and interceptors, here is - an excerpt of it: -

    +

    Parts

    +

    +

      +
    • kobalt-plugin.xml. A file that describes all the components (called "plug-in actors") of your plug-in, such as contributors.
    • +
    • Directives. Kotlin functions that users of your plug-in can invoke in their build file, such as kotlinProject or dependencies. These functions typically configure some data that your plug-in will later use to perform its functions.
    • +
    • Tasks. These tasks are invoked from the command line and ask your plug-ins to perform certain actions.
    • +
    • Properties. Plug-ins can export properties and read properties from other plug-ins.
    • +
    +

    + +

    kobalt-plugin.xml

    +

    + 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>
       <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: -

    + +

    + IPluginActors can be split in several categories: +

    +
      +
    • Plugins, which contain @Task annotations.
    • +
    • Interceptors, which transform data that Kobalt gives them.
    • +
    • Contributors, which produce additional data.
    • +
    +

    + 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. +

    +

    + If we look a the declarations of these classes, we can get an idea what they do +

     class JavaPlugin : ICompilerContributor, IDocContributor {
    - -

    - With this declaration, we know that the JavaPlugin contributes a compiler and a doc generator. -

    +

    + 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. -

    -

    Selection process

    -

    - 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: -

    +

    + This class is declaring that it wants to take part in the --init selection process, discussed below. +

    +

    List of plug-in actors

    +

    + Here is a list of actors (contributors and interceptors) that you can define in your plug-in. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Interface nameTypeDescription
    + IBuildConfigFieldContributorIInterceptor + Plug-ins that want to add custom fields to the generated BuildConfig class. +
    IBuildDirectoryInterceptorIInterceptor + 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. +
    ICompilerContributorIContributor + Plug-ins that know how to turn files into bytecodes should implement this interface. +
    ICompilerFlagContributorIContributor + + Plug-ins that need to add flags to the compiler. +
    ICompilerInterceptorIInterceptor + Plug-ins that implement this interface get a chance to alter the dependencies of a project (dependencies{}, dependenciesTest{}, ...) before Kobalt sees them. +
    IDocContributorIContributor + Plug-ins that know how to generate documentation out of source files should implement this interface. +
    IInitContributorIContributor 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... +
    IProjectContributorIContributor 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.
    IRepoContributorIContributor + 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. +
    IRunnerContributorIContributor + Plug-ins that can operate when the "run" task gets invoked should implement that interface. +
    + ISourceDirectoryContributorIContributor + + Plug-ins that add source directories. +
    + ISourceDirectoryInterceptorIInterceptor + Plug-ins that want to add, remove or alter the source directories should implement this interface. +
    + ITestRunnerContributorIContributor + Plug-ins that can operate when the "test" task gets invoked should implement that interface. +
    + ITestSourceDirectoryContributorIContributor + + Plug-ins that add test source directories. +
    +

    Selection process

    +

    + 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 {
         /**
    @@ -319,49 +277,45 @@ interface IProjectAffinity {
          */
         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: -

    - +

    + 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

    -

    - 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. -

    -

    - Imagine that you want to offer a boolean parameter publish to users of your plug-in, you start by creating a class to hold that parameter: -

    +if (project.sourceSuffix == ".java") 1 else 0 +

    Directives

    +

    + 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. +

    +

    + Imagine that you want to offer a boolean parameter publish to users of your plug-in, you start by creating a class to hold that parameter: +

     class Info(val publish: Boolean)
     
    -

    - Next, you create a directive that returns such a class and which also allows to configure it via the type safe builder pattern: -

    +

    + Next, you create a directive that returns such a class and which also allows to configure it via the type safe builder pattern: +

     @Directive
     public fun myConfig(init: Info.() -> Unit) = Info().apply { init() }
    -

    - The @Directive annotation is not enforced but you should always use it in order to help future tools (e.g. an IDEA plug-in) identify Kobalt directives so they can be treated differently from regular Kotlin functions. The code above defines a myConfig function that accepts a closure as an argument. It creates an Info - object, calls the init() function on it (which runs all the code inside that closure) and then return that Info object. -

    -

    - Users can now specify the following in their build file: -

    +

    + The @Directive annotation is not enforced but you should always use it in order to help future tools (e.g. an IDEA plug-in) identify Kobalt directives so they can be treated differently from regular Kotlin functions. The code above defines a myConfig function that accepts a closure as an argument. It creates an Info + object, calls the init() function on it (which runs all the code inside that closure) and then return that Info object. +

    +

    + Users can now specify the following in their build file: +

     // Build.kt
     ort.com.example.plugin.myConfig
    -
     myConfig {
         publish = true
     }
    -

    - If you need access to the project being built, just declare an additional parameter of type Project to your directive and have the user pass that project: -

    +

    + If you need access to the project being built, just declare an additional parameter of type Project to your directive and have the user pass that project: +

     @Directive
     public fun myConfig(project: Project, init: Info.() -> Unit) : Info {
    @@ -372,10 +326,9 @@ myConfig(project) {
         publish = true
     }
     
    -

    - The last piece of this puzzle is how you give this data back to your plug-in so it can act on it. In order to do this, you simply look up the name of your plug-in in the Plugins registry and invoke whatever function you need to run: -

    - +

    + The last piece of this puzzle is how you give this data back to your plug-in so it can act on it. In order to do this, you simply look up the name of your plug-in in the Plugins registry and invoke whatever function you need to run: +

     @Directive
     public fun myConfig(init: Info.() -> Unit) = Info().apply {
    @@ -383,19 +336,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

    -

    - 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

    -

    - 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

    +

    + 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

    +

    + 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 {
    @@ -403,100 +356,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: -

    -
    name
    -
    The name of the task, which will be used to invoke it from the command line.
    -
    description
    -
    The description of this command, which will be displayed if the user invokes the usage for the kobaltw command.
    -
    runBefore
    -
    A list of all the tasks that this task should run prior to.
    -
    runAfter
    -
    A list of all the tasks that should run before this task does.
    -
    alwaysRunAfter
    -
    A list of all the tasks that will always be run after this task if it's invoked.
    -
    -

    -

    - 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 exampleTaskResult
    runBefore = "compile" +

    + 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: +

    +
    name
    +
    The name of the task, which will be used to invoke it from the command line.
    +
    description
    +
    The description of this command, which will be displayed if the user invokes the usage for the kobaltw command.
    +
    runBefore
    +
    A list of all the tasks that this task should run prior to.
    +
    runAfter
    +
    A list of all the tasks that should run before this task does.
    +
    alwaysRunAfter
    +
    A list of all the tasks that will always be run after this task if it's invoked.
    +
    +

    +

    + 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 exampleTaskResult
    runBefore = "compile"
    kobalt-line-count:clean
     kobalt-line-count:exampleTask
     kobalt-line-count:compile
    -
    runAfter = "compile" +
    runAfter = "compile"
    kobalt-line-count:clean
     kobalt-line-count:compile
    -
    alwaysRunAfter = "compile" +
    alwaysRunAfter = "compile"
    kobalt-line-count:clean
     kobalt-line-count:compile
     kobalt-line-count:exampleTask
    -
    - -

    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 @Task - annotation on it). Plug-ins declare dynamic tasks by implementing the ITaskContributor - intrface: -

    +
    +

    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 @Task + annotation on it). Plug-ins declare dynamic tasks by implementing the ITaskContributor + intrface: +

     interface ITaskContributor {
         fun tasksFor(context: KobaltContext) : List<DynamicTask>
     }
    -

    - For example: -

    +

    + For example: +

     override fun tasksFor(context: KobaltContext) = listOf(
         DynamicTask(
    @@ -506,16 +455,16 @@ override fun tasksFor(context: KobaltContext) = listOf(
             closure = { project: Project ->
                 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 =====
    @@ -524,76 +473,67 @@ $ ./kobaltw --tasks
     $ ./kobaltw dynamicTask
     Running dynamictask
     
    - -

    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 properties: project-specific properties.
    • -
    • Plug-in properties: general properties that are applicable to no project - in particular.
    • -
    -

    Project properties

    - -

    - 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 properties: project-specific properties.
    • +
    • Plug-in properties: general properties that are applicable to no project + in particular.
    • +
    +

    Project properties

    +

    + 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)
    -          
    -

    Plug-in properties

    -

    - 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: -

    + +

    Plug-in properties

    +

    + 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
         context.pluginProperties.put(PLUGIN_NAME, "somePluginProperty", "someValue")
    -
         // Read a property from another plug-in
         val sourceDir = context.pluginProperties.get("pluginName", "somePluginProperty")
     }
     
    - -

    Documenting properties

    - -

    - Plug-ins that define properties should annotate them with the @ExportedPluginProperty or - @ExportedProjectPropertyannotation: -

    +

    Documenting properties

    +

    + Plug-ins that define properties should annotate them with the @ExportedPluginProperty or + @ExportedProjectPropertyannotation: +

         companion object {
             @ExportedProjectProperty
             const val BUILD_DIR = "buildDir"
     
    - -
    - -
    -
    - - - - - - - - - - - - -
    - +
    + +
    +
    + + + + + + + + + +
    + \ No newline at end of file