1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt-doc.git synced 2025-04-25 03:57:11 -07:00
kobalt-doc/documentation/index.html
2015-12-28 13:49:28 -08:00

624 lines
22 KiB
HTML

<html>
<head>
<title>
Kobalt, by Cedric Beust
</title>
<script type="text/javascript" src="../sh/scripts/shCore.js"></script>
<script type="text/javascript" src="../sh/scripts/shBrushJScript.js"></script>
<script type="text/javascript" src="../sh/scripts/shBrushJava.js"></script>
<script type="text/javascript" src="../sh/scripts/shBrushPlain.js"></script>
<script>
SyntaxHighlighter.defaults['gutter'] = false;
SyntaxHighlighter.defaults['toolbar'] = false;
SyntaxHighlighter.all();
</script>
<!--[if lt IE 9]><script src="../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<!--
<script src="../bootstrap/assets/js/ie-emulation-modes-warning.js"></script>
-->
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- Favicons -->
<!--
<link rel="icon" href="/favicon.ico">
-->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-238215-6', 'auto');
ga('send', 'pageview');
</script>
</head>
<body>
<div class="container">
<!-- Static navbar -->
<nav id="kobalt-navbar" class="navbar navbar-default">
</nav>
<!-- Main component for a primary marketing message or call to action -->
<div class="jumbotron">
<h1>Kobalt</h1>
<p>A universal build system for the exigent developer.</p>
<img src="../pics/auto-completion.png" class="img-rounded"/>
<!--
<p>
<a class="btn btn-lg btn-primary" href="../../components/#navbar" role="button">Download &raquo;</a>
</p>
-->
</div>
<div class="col-md-9">
<h2 class="section" id="downloading">Downloading and installing Kobalt</h2>
<p>
<a href="https://github.com/cbeust/kobalt/releases/latest">Download the zip file</a> then unzip it in a location we'll call <code>KOBALT_HOME</code>:
</p>
<pre class="brush:plain">
cd $KOBALT_HOME
unzip kobalt-xxx.zip
</pre>
<p>
Change to your project directory and call the <code>kobaltw</code> command with <code>--init</code>:
</p>
<pre class="brush:plain">
cd ~/java/project
$KOBALT_HOME/kobaltw --init
</pre>
<p>
This command will do two things:
</p>
<ol>
<li>Create a default <code>kobalt/src/Build.kt</code> file based on what was found there.
<li>Install the Kobalt Wrapper in your current directory (script `kobaltw`) and in the <code>kobalt/</code> directory. From now on, you can just use <code>./kobaltw</code> to build and you can ignore <code>$KOBALT_HOME</code>.
</ol>
<p>
You can now attempt to build your project with Kobalt:
</p>
<pre class="brush:plain">
./kobaltw assemble
</pre>
If your project follows a regular build structure (e.g. <a href="https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html">Maven's hierarchy</a>), this should compile your file and create a .jar file. If not, you will have to make a few edits to your <code>Build.kt</code>.
As of this writing, Kobalt supports Java and Kotlin projects.
<h2 class="section" id="structure">Structure of a build file</h2>
<h3 class="section" indent="1" id="general-concepts">General concepts</h3>
<p>
The build file is typically called <code>Built.kt</code> and it is a valid Kotlin file. 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:
</p>
<pre class="brush:java">
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")
}
</pre>
Here are a few noteworthy details about this small build file:
<ul>
<li>You have now declared a variable called <code>kobalt</code> which you can reuse further in your build file, should you ever need to.
<li>You can specify the directory of the project, which means that one build file can be used to build multiple projects.
<li>The functions <code>kotlinProject</code> and <code>homeDir</code> are supplied by Kobalt and are referred to as "directives"
</ul>
<p>
In terms of syntax, there are basically three different ways to specify values in a build file:
</p>
<ul>
<li>Individual values for primitives (numbers, strings) are a straight equals sign:
<pre class="brush:java">
name = "kobalt"</pre>
</li>
<li>
Parameters that can receive multiple values are usually captured by function calls, so you use parentheses, as usual in Kotlin:
<pre class="brush:java">
compile("dep1", "dep2", "dep2")</pre>
</li>
<li>
Complex objects are passed as closures, so you use curly braces to define them:
<pre class="brush:java">
dependencies {
...
}</pre>
</li>
</ul>
<p>
Remember that a build file is a valid Kotlin source, so you can use function calls instead of literal values, or any other correct Kotlin code in your build file:
</p>
<pre class="brush:java">
version = readVersion()</pre>
<h3 class="section" indent="1" id="directives">Directives</h3>
<p>
Now that we have declared a project, we can use it to configure additional steps of our build, such as how to assemble it (creating jar and other files):
</p>
<pre class="brush:java;highlight=5,6,7,8">
import com.beust.kobalt.plugin.packaging.assemble
val kobalt = kotlinProject {
// ...
assemble {
jar {
}
}
}
</pre>
<p>
This is the simplest jar declaration you can have. You can trigger the creation of this jar file by invoking the task <code>"assemble"</code> from the command line. Note the presence of the corresponding <code>import</code>: without it, your build file will not compile. Another interesting details is that the <code>assemble</code> function we just imported is an extension function on the <code>Project</code> class, which is how the import makes it legal to call <code>assemble</code> in the middle of our project. If you remove the import, that line will no longer compile.
</p>
<p>
The <code>jar</code> directive accepts various settings, so let's be a bit more specific. And let's add a zip file too:
</p>
<pre class="brush:java">
assemble {
jar {
fatJar = true
manifest {
attributes("Main-Class", "com.beust.FileHavingMainKt")
}
}
zip {
include("kobaltw")
include(from("$buildDirectory/libs"), to("kobalt/wrapper"),
"$projectName-$version.jar")
include(from("modules/wrapper/$buildDirectory/libs"), to("kobalt/wrapper"),
"$projectName-wrapper.jar")
}
</pre>
<p>
Our jar file is now declared to be a "fat jar" (which means it will include all its dependencies) and we specified a <code>Main-Class</code> to the jar Manifest, which means we will be able to invoke it with <code>java -jar kobalt-0.61.jar</code>. If you don't like this name, you can override it with a <code>name = "myName.jar"</code> statement. <code>FileHavingMain</code> is the class name in the <code>com.beust</code> package that contains a <code>main()</code> function.
</p>
<p>
The zip directive follows a similar structure, although here we are specifying which file we want to include. For more details on the <code>packaging</code> plug-in, please see its documentation.
</p>
<h3 class="section" indent="1" id="inline-tasks">Inline tasks</h3>
<p>
Since <code>Build.kt</code> is a valid Kotlin file, you can write arbitrary Kotlin code in it,
including defining tasks. If you ever need to perform an operation that is not supported by an
existing plug-in and it would be overkill to write a plug-in just for it, you can define that
task directly in your build file, including specifying its run dependencies so that it will
be executed exactly when you want it. Here is an example from <a href="https://github.com/cbeust/testng/blob/master/kobalt/src/Build.kt#L53">TestNG's own build file</a>:
</p>
<pre class="brush:java">
@Task(name = "createVersion", runBefore = arrayOf("compile"), runAfter = arrayOf("clean"))
fun taskCreateVersion(project: Project) : TaskResult {
val path = "org/testng/internal"
with(arrayListOf&lt;String&gt;()) {
File("src/main/resources/$path/VersionTemplateJava").forEachLine {
add(it.replace("@version@", VERSION))
}
File("src/generated/java/$path/Version.java").writeText(joinToString("\n"))
}
return TaskResult()
}</pre>
<p>
This tasks takes a template file and replaces all occurrences of the string <code>"@version@"</code> with the actual version of the project. Obviously, this task is very specific to TestNG's own build and it wasn't worth writing a plug-in ftor this. Note the attributes <code>runBefore</code> and <code>runAfter</code>, which specify when this task will run. You can find more information about tasks in the <a href="http://beust.com/kobalt/plug-in-development/index.html#tasks">plug-in development section</a>.
</p>
<h3 class="section" indent="1" id="dependencies">Dependencies</h3>
<p>
You can declare compile and test dependencies as follows:
</p>
<pre class="brush:java">
dependencies {
compile("com.beust:jcommander:1.48",
"com.beust:klaxon:0.14")
}
dependenciesTest {
compile("org.testng:testng:6.9.5")
}
</pre>
<p>
You can also specify local dependencies with the <code>file</code> directive:
</p>
<pre class="brush:java">
dependencies {
compile(file("libs/async-http.jar"))
}
</pre>
<h2 class="section" id="maven-repos">Maven repos</h2>
<h3 class="section" indent="1" id="maven-repos-unauthenticated">Unauthenticated repos</h3>
<p>
Kobalt already knows the location of the most popular Maven repos (Maven Central, JCenter, JBoss) but you can add repos with the <code>repos()</code> directive:
</p>
<pre class="brush:plain">
val repos = repos("https://dl.bintray.com/cbeust/maven/")</pre>
<p>
By default, this directive takes URL's as strings, but you can also use local
files with the <code>files</code> directive:
</p>
<pre class="brush:plain">
val repos = repos(file("/some/local/directory"))</pre>
<p>
The <code>homeDir()</code> directive can also come in handy when you want
to specify a directory starting at your home directory:
</p>
<pre class="brush:plain">
val repos = repos(file(homeDir("some/directory/in/your/home")))</pre>
<h3 class="section" indent="1" id="maven-repos-authenticated">Authenticated repos</h3>
<p>
If one of your repos requires basic authentication, you can supply its credentials
in your <code>local.properties</code> file by specifying keys and values following the format:
</p>
<pre class="brush:plain">
authUrl.{host}.username=xxx
authUrl.{host}.password=xxx
</pre>
<p>
Note that the host is just the host name portion of the URL (excluding "http://",
port number, slash and path). For example, for the repo
<code>"https://dl.bintray.com/cbeust/maven/"</code>, the credentials would be:
</p>
<pre class="brush:plain">
authUrl.dl.bintray.com.username=xxx
authUrl.dl.bintray.com.password=xxx
</pre>
<p>
If only one of <code>username</code> or <code>password</code> is specified,
the build will abort with an error.
</p>
<h2 class="section" id="using-plug-ins">Using plug-ins</h2>
<p>
Kobalt comes with a few preconfigured plug-ins but you will want to include external ones as well, which can be downloaded either from a Maven repository (Sonatype, JCenter, ...) or from a local file.
</p>
<p>
First of all, let's take a quick look at the tasks available in the default distribution (your actual output might differ somewhat):
</p>
<pre class="brush:plain">
$ ./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
</pre>
<p>
Let's modify our build to include a plug-in. We do this by adding a call to the <code>plugins</code> directive on top of the build file:
</p>
<pre class="brush:java">
val repos = repos("https://dl.bintray.com/cbeust/maven/")
val p = plugins("com.beust:kobalt-example-plugin:0.42")
</pre>
<p>
Now, run the <code>--tasks</code> command again:
</p>
<pre class="brush:plain">
$ ./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
</pre>
Notice the new <code>"coverage"</code> task, provided by the plug-in <code>kobalt-example-plugin</code> 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.
<h2 class="section" id="multiple-projects">Multiple projects</h2>
<p>
You can specify more than one project in a build file, simply by declaring them:
</p>
<pre class="brush:java">
val p1 = javaProject { ... }
val p2 = kotlinProject { ... }
</pre>
<p>
If some of your projects need to be built in a certain order, you can specify dependencies when you create your project. For example:
</p>
<pre class="brush:java">
val p2 = kotlinProject(p1) { ... }
</pre>
<p>
This declares that the Kotlin project <code>p2</code> depends on <code>p1</code>, which means that the project <code>p1</code> will be built first.
</p>
<p>
You can also run tasks for a specific project only as follows:
</p>
<pre class="brush:plain">
./kobaltw p2:assemble
</pre>
This will run the <code>assemble</code> task only for the <code>p2</code>, instead of running it for all projects.
<h2 class="section" id="command-line">Command line</h2>
<p>
Here are the options that you can pass to <code>./kobaltw</code>:
</p>
<table style="font-size: 14px" class="table table-striped">
<colgroup>
<col span="1" style="width: 25%;">
<col span="1" style="width: 10%;">
<col span="1" style="width: 10%;">
<col span="1" style="width: 20%;">
<col span="1" style="width: 40%;">
</colgroup>
<thead>
<tr>
<td>Name</td>
<td>Type</td>
<td>Default</td>
<td>Description</td>
<td>Details</td>
</tr>
</thead>
<tr>
<td><code>--buildFile</code></td>
<td>File</td>
<td>kobalt/src/Build.kt</td>
<td>Specify a build file.</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>
<td><code>--checkVersions</code></td>
<td>Boolean</td>
<td>false</td>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:
<pre class="brush:plain">
$ ./kobaltw --checkVersions
New versions found:
com.beust:klaxon:0.14
org.testng:testng:6.9.5
</pre>
</td>
</tr>
<tr>
<td><code>--dryRun</code></td>
<td>Boolean</td>
<td>false</td>
<td>Display the tasks about to be run without actually running them.</td>
<td>Use this option to get an idea of what the build will run without actually building anything.</td>
</tr>
<tr>
<td><code>--init</code></td>
<td>Boolean</td>
<td>false</td>
<td>Initialize a project for Kobalt.</td>
<td>This option will create a build file in the current directory (unless one already exists) and will install the Kobalt wrapper.</td>
</tr>
<tr>
<td><code>--log</code></td>
<td>Integer (0..3)</td>
<td>1</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>
</tr>
<tr>
<td><code>--resolve</code></td>
<td>Maven id<br/>(e.g.&nbsp;<code>"com.beust:kobalt:0.228"</code>)</td>
<td>N/A</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>
</tr>
<tr>
<td><code>--tasks</code></td>
<td>Boolean</td>
<td>false</td>
<td>List the tasks available.</td>
<td>Note that the available tasks will vary depending on which projects are in your build file.</td>
</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>
<h2 class="section" id="publishing">Publishing</h2>
<p>
Kobalt supports JCenter natively so you can upload your project and make it available on JCenter very easily.
</p>
<p>
First of all, make sure you specified the group, artifactId and version of your project, as required by Maven:
</p>
<pre class="brush:java">
val kobalt = kotlinProject {
group = "com.beust"
artifactId = "kobalt"
version = "0.72"
</pre>
<p>
Next, create a file <code>local.properties</code> in the root directory of your project with the following keys:
</p>
<pre class="brush:plain">
bintray.user=...
bintray.apikey=...
# Optional. Include this if you want to upload to your org's repo instead of your own.
# bintray.organization=...
</pre>
<p>
The values for the <code>user</code> and <code>apikey</code> keys can be found in your bintray profile, as described <a href="https://bintray.com/docs/usermanual/interacting/interacting_editingyouruserprofile.html#anchorAPIKEY">here</a>. Note that you should <b>not</b> check this <code>local.properties</code> file into your source control (so add it to <code>.gitignore</code>). Next, make sure that your build creates a jar file (using the <code>packaging</code> directive, as explained above).
</p>
<p>
Now, all you need to do is to upload your package:
</p>
<pre class="brush:plain">
./kobaltw uploadJcenter
</pre>
<h2 class="section" id="profiles">Profiles</h2>
<p>
Profiles allow you to run altered versions of your build file by using command
line parameters.
</p>
<p>
You start by defining boolean values initialized to <code>false</code> in your build file:
</p>
<pre class="brush:java">
val experimental = false
val premium = false
</pre>
<p>
Then you use this variable wherever you need it in your build file:
</p>
<pre class="brush:java">
val p = javaProject {
name = if (experimental) "project-exp" else "project"
version = "1.3"
</pre>
<p>
Finally, you invoke <code>./kobaltw</code> with the <code>--profiles</code> parameter followed by the profiles you want to activate, separated by a comma:
</p>
<pre class="brush:plain">
./kobaltw -profiles experimental,premium assemble
</pre>
<p>
Keep in mind that since your build file is a real Kotlin source file,
you can use these profile variables pretty much anywhere, e.g.:
</p>
<pre class="brush:java">
dependencies {
if (experimental)
"com.squareup.okhttp:okhttp:2.4.0"
else
"com.squareup.okhttp:okhttp:2.5.0",
</pre>
<h2 class="section" id="sources">Sources and license</h2>
<p>
Kobalt is <a href="https://github.com/cbeust/kobalt/blob/master/LICENSE.txt">licensed under Apache 2.0</a> and is <a href="http://github.com/cbeust/kobalt">currently hosted on github.</a>
</p>
<h2 class="section" id="discuss">Discuss Kobalt</h2>
<p>
If you are interested in discussing Kobalt related topics with other fellow users or developers, you have several options:
</p>
<ul>
<li>Live discussions are happening on Kotlin's Slack Channel, managed by JetBrains. You can get an automated invitation <a href="http://kotlinslackin.herokuapp.com/">here</a> and then, just join the <code>#kobalt</code> channel.
</li>
<li><a href="https://groups.google.com/forum/#!forum/kobalt-users">Join <code>kobalt-users</code>, the mailing-list for Kobalt users.</a></li>
<li><a href="https://groups.google.com/forum/#!forum/kobalt-dev">Join <code>kobalt-dev</code>, the mailing-list for Kobalt developers</a>. This mailing-list is for people interested in writing code for Kobalt, either the core, or writing plug-ins, or just to follow various technical discussions about Kobalt's internals.</li>
</ul>
<p>
</p>
</div>
<!-- Table of contents -->
<div class="col-md-3" id="table-of-contents">
</div>
</div> <!-- /container -->
<!-- Bootstrap core JavaScript
================================================== -->
<!-- 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="../bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../js/kobalt.js"></script>
<script>generateKobalt(1);</script>
<!--
<script src="../bootstrap/dist/js/docs.min.js"></script>
-->
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<!--
<script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
-->
</body>