diff --git a/contributing/index.html b/contributing/index.html index 43523e0..aab801b 100644 --- a/contributing/index.html +++ b/contributing/index.html @@ -1,107 +1,95 @@ - - + <head> + <title> + Kobalt, by Cedric Beust + + + + + + + + + + + + + + + + + +
+ + + +
+

Contributing to Kobalt

+
+ +
+

License, Source code & Issues

+

+ Kobalt is licensed under Apache 2.0 +

+

+ You can contribute code and report issues at the Kobalt Github Repo +

- Kobalt, by Cedric Beust +

Discuss Kobalt

+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
-

Contributing to Kobalt

-

Interested in contributing to Kobalt? This page explains how to configure your development environment.

- -
- - -
- -

Launch configuration

- -

- Kobalt's main class is com.beust.kobalt.MainKt. Here is a typical launch configuration: -

-

- -

- -

- A few observations: -

    -
  • You can ask Kobalt to build external projects by specifying a non-empty "Working Directory".
  • -
  • The default log level is 1. 2 is useful for debugging and 3 will be extremely verbose.
  • -
  • Another command line parameter worth of notice is --dev, which will add the class +

    Launch configuration

    +

    Here is how to configure your development environment.

    +

    + Kobalt's main class is com.beust.kobalt.MainKt. Here is a typical launch configuration: +

    +

    + +

    +

    + A few observations: +

      +
    • You can ask Kobalt to build external projects by specifying a non-empty "Working Directory".
    • +
    • The default log level is 1. 2 is useful for debugging and 3 will be extremely verbose.
    • +
    • Another command line parameter worth of notice is --dev, which will add the class name and thread information to each log line.
    • -
    • Checking the "Single instance" box is useful to avoid duplicating these launch configurations.
    • -
    - -

    -
- - -
-
- - - - - - - - - - - - - +
  • Checking the "Single instance" box is useful to avoid duplicating these launch configurations.
  • + +

    +
    + +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/css/kobalt.css b/css/kobalt.css index 49911f8..a95cda2 100644 --- a/css/kobalt.css +++ b/css/kobalt.css @@ -2,6 +2,10 @@ * Kobalt CSS */ +.features { + font-size: 1.5em; +} + code { background-color: #ffffff; } diff --git a/documentation/index.html b/documentation/index.html index 398300e..5e41e8d 100644 --- a/documentation/index.html +++ b/documentation/index.html @@ -57,9 +57,7 @@
    -

    Kobalt

    -

    A universal build system for the exigent developer.

    - +

    Documentation

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

    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 kobalt/src/Build.kt

    + + Here for example is the Build.kt for wasabi http framework +
    +import com.beust.kobalt.*
    +import com.beust.kobalt.plugin.packaging.assemble
    +import com.beust.kobalt.plugin.kotlin.*
    +
    +val kotlin_version = "1.0.0-beta-4583"
    +
    +val p = kotlinProject {
    +
    +    name = "wasabi"
    +    group = "com.example"
    +    artifactId = name
    +    version = "0.1"
    +
    +    //tells Kobalt to also search here for dependencies
    +    val repos = repos("http://oss.sonatype.org/content/repositories/snapshots") 
    +
    +    dependencies {
    +        compile("org.jetbrains.kotlin:kotlin-stdlib:" + kotlin_version)
    +        compile("org.jetbrains.kotlin:kotlin-reflect:" + kotlin_version)
    +
    +        compile("com.fasterxml.jackson.core:jackson-core:2.6.4")
    +        compile("com.fasterxml.jackson.core:jackson-databind:2.6.4")
    +        compile("com.fasterxml.jackson.core:jackson-annotations:2.6.4")
    +        compile("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.6.3")
    +        compile("com.fasterxml.woodstox:woodstox-core:5.0.1")
    +
    +        compile("io.netty:netty-all:4.0.31.Final")
    +        compile("commons-codec:commons-codec:1.6")
    +        compile("commons-logging:commons-logging:1.1.1")
    +        compile("com.netflix.rxjava:rxjava-core:0.20.0-RC4")
    +        compile("org.slf4j:slf4j-api:1.7.5")
    +        compile("org.slf4j:slf4j-simple:1.7.5")
    +        compile("joda-time:joda-time:2.3")
    +    }
    +
    +    //these are only downloaded when running the test task
    +    dependenciesTest {
    +        compile("junit:junit:4.9")
    +        compile("org.mockito:mockito-all:1.9.5")
    +        compile("org.apache.httpcomponents:httpcore:4.3.3")
    +        compile("org.apache.httpcomponents:httpclient:4.5.1")
    +    }
    +
    +    //tells kobalt to produce a jar
    +    assemble {
    +        jar {
    +        }
    +    }
    +}
    +
    + +

    4. In Intellij IDEA, Sync Build File

    +

    + If you're using Intellij IDEA, make sure you've installed the Kobalt plugin and then go to Kobalt -> Sync Build File. This will download dependencies in a way that IDEA understand so you no loger get errors. +

    + +
    + +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/home/index.html b/home/index.html index dc8a716..d417ab7 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

    +
      +
    • Clean, easy-to-use syntax for build files
    • +
    • Build file auto-completion from your favorite IDE
    • +
    • Intuitive plug-in architecture
    • +
    • Fast builds
    • +

    @@ -110,7 +116,7 @@ val jcommander = javaProject {

  • An agnostic build tool. Kobalt can be used to build Kotlin and Java projects today but it's capable to build anything: any language (JVM or not) or platform (Android, Spring, ...). -

    The path to Kobalt 1.0

    +

    Status

    Kobalt is currently in Beta but I'm already using it to build most of my projects. Here are links to a few build files you can inspect to get a feel for what Kobalt enables: @@ -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