From e8392bb1eafc7ff016a039e270f9ec8fa6f4f59b Mon Sep 17 00:00:00 2001
From: Cedric Beust
KOBALT_HOME
:
+
++cd $KOBALT_HOME +unzip kobalt-xxx.zip ++ +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: + +
Build.kt
file in your current directory based on what was found there.
+kobalt/
directory. From now on, you can just use ./kobaltw
to build and you can ignore $KOBALT_HOME
.
++./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.
+
+Built.kt
and it is a valid Kotlin file. Typically, it contains imports, the declaration of one or more projects and the declaration of additional configurations (e.g. packaging, publishing, etc...). Since it's a Kotlin file, it can also contain any class or function you need:
+
++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") +} ++ +Here are a few noteworthy details about this small build file: + +
kobalt
which you can reuse (see below).
+kotlinProject
and homeDir
are supplied by Kobalt and are sometimes referred to as "directives"
++import com.beust.kobalt.plugin.packaging.packaging + +// ... + +val packKobalt = packaging(kobalt) { + jar { + } +} ++ +This is the simplest jar declaration you can have. You can trigger the creation of this jar file by invoking the task
"assemble"
. Note that we passed the kobalt
variable to the packaging
function, so we make it clear which project we are currently configuring for packaging. The jar
directive accepts various settings, so let's be a bit more specific. And let's add a zip file too:
+
++val packKobalt = packaging(kobalt) { + jar { + fatJar = true + manifest { + attributes("Main-Class", "com.beust.kobalt.KobaltPackage") + } + } + zip { + include("kobaltw") + include(from("${kobalt.buildDirectory}/libs"), + to("kobalt/wrapper"), + "${kobalt.name}-${kobalt.version}.jar", + "${kobalt.name}-wrapper.jar") + } +} ++ +Our jar file is now declared to be a "fat jar" (which means it will include all its dependencies) and we specified a
Main-Class
to the jar Manifest, which means we will be able to invoke it with java -jar kobalt-0.61.jar
. If you don't like this name, you can override it with a name = "myName.jar"
statement.
+
+
+
+The zip directive follows a similar structure, although here we are specifying which file we want to include. For more details on the packaging
plug-in, please see its documentation.
+
+
+dependencies { + compile("com.beust:jcommander:1.48", + "com.beust:klaxon:0.14") +} + +dependenciesTest { + compile("org.testng:testng:6.9.5") +} ++ +
repos()
directive:
+
++val repos = repos("https://dl.bintray.com/cbeust/maven/") ++ +
+ +First of all, let's take a quick look at the tasks available in the default distribution (your actual output might differ somewhat): + +
+$ ./kobaltw --tasks + ===== java ===== + compile Compile the project + compileTest Compile the tests + test Run the tests + clean Clean the project + + ===== publish ===== + generatePom Generate the .pom file + uploadJcenter Upload the artifacts to JCenter + + ===== packaging ===== + assemble Package the artifacts ++ +Let's modify our build to include a plug-in. We do this by adding a call to the
plugins
directive on top of the build file:
+
++val repos = repos("https://dl.bintray.com/cbeust/maven/") +val p = plugins("com.beust:kobalt-example-plugin:0.42") ++ +Now, run the
--tasks
command again:
+
++$ ./kobaltw --tasks + ===== java ===== + compile Compile the project + + ===== publish ===== + generatePom Generate the .pom file + uploadJcenter Upload the artifacts to JCenter + + ===== kobalt-example-plugin ===== + coverage Run coverage + + ===== packaging ===== + assemble Package the artifacts ++ +Notice the new
"coverage"
task, provided by the plug-in kobalt-example-plugin
that we just included. With the simple action of declaring the plug-in, it is now fully loaded and available right away. Of course, such plug-ins can allow or require additional configuration with their own directives. Please read the plug-in developer documentation for more details.
+
++ +First of all, make sure you specified the group, artifactId and version of your project, as required by Maven: + +
+val kobalt = kotlinProject { + group = "com.beust" + artifactId = "kobalt" + version = "0.72" ++ +Next, create a file
local.properties
in the root directory of your project with the following keys:
+
++bintray.user=... +bintray.apikey=... ++ +The values for the
user
and apikey
keys can be found in your bintray profile, as described here. Note that you should not check this local.properties
file into your source control (so add it to .gitignore
).
+
++ +Make sure that your build creates a jar file (using `packaging`, as explained above). + +
+ +Now, all you need to do is to upload your package: + +
+./gradlew uploadJcenter ++ +
+dependencies { + compile("com.beust:kobalt:0.61") +} ++ +
+val p = packaging(examplePlugin) { + jar { + manifest { + attributes("Kobalt-Plugin-Class", "com.beust.kobalt.example.ExamplePlugin") + } + } +} ++ +
BasePlugin
BasePlugin
and implements its apply()
method and name
variable:
+
++public class ExamplePlugin : BasePlugin() { + override val name = "kobalt-example-plugin" + + override fun apply(project: Project) { + println("Applying plugin ${name} with project ${project}") + } +} ++ +
@Task
annotation:
+
++@Task(name = "coverage", description = "Run coverage", + runAfter = arrayOf("compile")) +public fun coverage(project: Project): TaskResult { + println("Running the coverage on project ${project}") + return TaskResult() +} ++ +
TaskResult
object, which can be initialized with false
if the task didn't succeed for some reason.
+ kobaltw
command (e.g. "./kobaltw coverage"
)
+ "./kobaltw --tasks"
+ runAfter
and runBefore
let you specify the dependencies of your task. In this example plug-in, we want to calculate the coverage of the project so it makes sense to run after the "compile"
task.
+
+
+These can be either straight functions or extension functions. For example, here is the kotlinProject
directive:
+
+
+@Directive +public fun kotlinProject(init: KotlinProject.() -> Unit): KotlinProject { + val result = KotlinProject() + result.init() + return result +} ++ +This function returns a
KotlinProject
and the user can then override variables or invoke methods from this class in their build file:
+
++val kobalt = kotlinProject { + name = "kobalt" + group = "com.beust" +... ++ +Using an extension function to define a directive allows you to add new functions to Kobalt classes. For example, currently, a project can have
"dependencies"
and "dependenciesTest"
. For a coverage plug-in, we would want to add a "dependenciesCoverage"
section, which can be easily done by defining an extension function on Project
:
+
++@Directive +public fun Project.dependenciesCoverage(ini: Dependencies.() -> Unit) : Dependencies { + val result = Dependencies() + result.init() + return result +} ++ +And we can now use: + +
+val p = kotlinProject { + dependenciesCoverage("com.example:foo:0.1") +} ++ + +
KOBALT_HOME
:
+-cd $KOBALT_HOME -unzip kobalt-xxx.zip -- -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: - -
Build.kt
file in your current directory based on what was found there.
-kobalt/
directory. From now on, you can just use ./kobaltw
to build and you can ignore $KOBALT_HOME
.
--./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.
-
-Built.kt
and it is a valid Kotlin file. Typically, it contains imports, the declaration of one or more projects and the declaration of additional configurations (e.g. packaging, publishing, etc...). Since it's a Kotlin file, it can also contain any class or function you need:
-
--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") -} -- -Here are a few noteworthy details about this small build file: +
kobalt
which you can reuse (see below).
-kotlinProject
and homeDir
are supplied by Kobalt and are sometimes referred to as "directives"
+ -import com.beust.kobalt.plugin.packaging.packaging - -// ... - -val packKobalt = packaging(kobalt) { - jar { - } -} -- -This is the simplest jar declaration you can have. You can trigger the creation of this jar file by invoking the task
"assemble"
. Note that we passed the kobalt
variable to the packaging
function, so we make it clear which project we are currently configuring for packaging. The jar
directive accepts various settings, so let's be a bit more specific. And let's add a zip file too:
-
--val packKobalt = packaging(kobalt) { - jar { - fatJar = true - manifest { - attributes("Main-Class", "com.beust.kobalt.KobaltPackage") - } - } - zip { - include("kobaltw") - include(from("${kobalt.buildDirectory}/libs"), - to("kobalt/wrapper"), - "${kobalt.name}-${kobalt.version}.jar", - "${kobalt.name}-wrapper.jar") - } -} -- -Our jar file is now declared to be a "fat jar" (which means it will include all its dependencies) and we specified a
Main-Class
to the jar Manifest, which means we will be able to invoke it with java -jar kobalt-0.61.jar
. If you don't like this name, you can override it with a name = "myName.jar"
statement.
-
-
-
-The zip directive follows a similar structure, although here we are specifying which file we want to include. For more details on the packaging
plug-in, please see its documentation.
-
-
-dependencies { - compile("com.beust:jcommander:1.48", - "com.beust:klaxon:0.14") -} - -dependenciesTest { - compile("org.testng:testng:6.9.5") -} -- -
repos()
directive:
-
--val repos = repos("https://dl.bintray.com/cbeust/maven/") -- -
- -First of all, let's take a quick look at the tasks available in the default distribution (your actual output might differ somewhat): - -
-$ ./kobaltw --tasks - ===== java ===== - compile Compile the project - compileTest Compile the tests - test Run the tests - clean Clean the project - - ===== publish ===== - generatePom Generate the .pom file - uploadJcenter Upload the artifacts to JCenter - - ===== packaging ===== - assemble Package the artifacts -- -Let's modify our build to include a plug-in. We do this by adding a call to the
plugins
directive on top of the build file:
-
--val repos = repos("https://dl.bintray.com/cbeust/maven/") -val p = plugins("com.beust:kobalt-example-plugin:0.42") -- -Now, run the
--tasks
command again:
-
--$ ./kobaltw --tasks - ===== java ===== - compile Compile the project - - ===== publish ===== - generatePom Generate the .pom file - uploadJcenter Upload the artifacts to JCenter - - ===== kobalt-example-plugin ===== - coverage Run coverage - - ===== packaging ===== - assemble Package the artifacts -- -Notice the new
"coverage"
task, provided by the plug-in kobalt-example-plugin
that we just included. With the simple action of declaring the plug-in, it is now fully loaded and available right away. Of course, such plug-ins can allow or require additional configuration with their own directives. Please read the plug-in developer documentation for more details.
-
-- -First of all, make sure you specified the group, artifactId and version of your project, as required by Maven: - -
-val kobalt = kotlinProject { - group = "com.beust" - artifactId = "kobalt" - version = "0.72" -- -Next, create a file
local.properties
in the root directory of your project with the following keys:
-
--bintray.user=... -bintray.apikey=... -- -The values for the
user
and apikey
keys can be found in your bintray profile, as described here. Note that you should not check this local.properties
file into your source control (so add it to .gitignore
).
-
-- -Make sure that your build creates a jar file (using `packaging`, as explained above). - -
- -Now, all you need to do is to upload your package: - -
-./gradlew uploadJcenter -- -
-dependencies { - compile("com.beust:kobalt:0.61") -} -- -
-val p = packaging(examplePlugin) { - jar { - manifest { - attributes("Kobalt-Plugin-Class", "com.beust.kobalt.example.ExamplePlugin") - } - } -} -- -
BasePlugin
BasePlugin
and implements its apply()
method and name
variable:
-
--public class ExamplePlugin : BasePlugin() { - override val name = "kobalt-example-plugin" - - override fun apply(project: Project) { - println("Applying plugin ${name} with project ${project}") - } -} -- -
@Task
annotation:
-
--@Task(name = "coverage", description = "Run coverage", - runAfter = arrayOf("compile")) -public fun coverage(project: Project): TaskResult { - println("Running the coverage on project ${project}") - return TaskResult() -} -- -
TaskResult
object, which can be initialized with false
if the task didn't succeed for some reason.
- kobaltw
command (e.g. "./kobaltw coverage"
)
- "./kobaltw --tasks"
- runAfter
and runBefore
let you specify the dependencies of your task. In this example plug-in, we want to calculate the coverage of the project so it makes sense to run after the "compile"
task.
-
-These can be either straight functions or extension functions. For example, here is the kotlinProject
directive:
+With this disclaimer, why did I decide to write Kobalt?
-
-@Directive -public fun kotlinProject(init: KotlinProject.() -> Unit): KotlinProject { - val result = KotlinProject() - result.init() - return result -} -+
KotlinProject
and the user can then override variables or invoke methods from this class in their build file:
+I give a lot of credit to Gradle for having open a brand new avenue in build tools but despite all its power and flexibility and the fact that I've used Gradle for more than five years, I've never really felt comfortable or fluent with it. Even today, I regularly find myself spending a lot of time on StackOverflow whenever I need to do something a bit out of the ordinary with my Gradle builds.
--val kobalt = kotlinProject { - name = "kobalt" - group = "com.beust" -... -+I suspect a part of it is due to Groovy which, even though it started gaining some static type features these past years, remains at its heart a dynamically typed language. This has two consequences: -Using an extension function to define a directive allows you to add new functions to Kobalt classes. For example, currently, a project can have
"dependencies"
and "dependenciesTest"
. For a coverage plug-in, we would want to add a "dependenciesCoverage"
section, which can be easily done by defining an extension function on Project
:
+-@Directive -public fun Project.dependenciesCoverage(ini: Dependencies.() -> Unit) : Dependencies { - val result = Dependencies() - result.init() - return result -} -+
-val p = kotlinProject { - dependenciesCoverage("com.example:foo:0.1") -} -+