Archive for November, 2015

The Kobalt diaries: profiles

When I started thinking about how profiles should work in Kobalt, I realized that the simplest approach I’d like to see in a build tool is defining a boolean variable and having if statements in my build file. So that’s exactly how Kobalt’s profiles are implemented.

You start by defining boolean values initialized to false in your build file:

  val experimental = false
  val premium = false

Then you use this variable wherever you need it in your build file:

  val p = javaProject {
      name = if (experimental) "project-exp" else "project"
      version = "1.3"
      ...

Finally, you invoke ./kobaltw with the --profiles parameter followed by the profiles you want to activate, separated by a comma:

  ./kobaltw -profiles experimental,premium assemble

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

dependencies {
    if (experimental)
        "com.squareup.okhttp:okhttp:2.4.0"
    else
        "com.squareup.okhttp:okhttp:2.5.0",

And that’s it.

The full series of articles on Kobalt can be found here.

The Kobalt diaries: it’s the little things

When I embarked on the ridiculously ambitious goal of writing a build tool, I had plans to tackle both big problems and small problems. My previous (and probably future) blog post cover the big problems such as performance, plug-in architecture and DSL syntax, but in this post, I’m going to cover a few little things that I was quite happy to finally be able to get from my build tool.

I’ve always found it a hassle to keep up with the latest versions of the dependencies of my build, especially since it’s its job to tell me. Therefore, Kobalt has a handy --checkVersions parameter that will check to see if it can find any new version of your dependencies:

$ ./kobaltw --checkVersions
New versions found:
        org.jetbrains.kotlin:kotlin-compiler-embeddable:1.0.0-beta-2423
        org.jetbrains.kotlin:kotlin-stdlib:1.0.0-beta-2423
        com.squareup.okhttp:okhttp:2.6.0
        com.squareup.retrofit:retrofit:2.0.0-beta2

Another convenient switch is --resolve, which looks up a dependency and gives you some information about it, such as which Maven repo it is found in and its own dependency tree. You can also use an id without a version (e.g. org.testng:testng:) to ask Kobalt to find the most recent version of that artifact:

$ ./kobaltw --resolve org.testng:testng:
╔══════════════════════════════════════════════════════════════════════════════════╗
║                                     org.testng:testng:                           ║
║           http://repo1.maven.org/maven2/org/testng/testng/6.9.9/testng-6.9.9.jar ║
╚══════════════════════════════════════════════════════════════════════════════════╝
╟ junit:junit:4.10
║      ╙ org.hamcrest:hamcrest-core:1.1
╟ com.beust:jcommander:1.48
╟ org.apache.ant:ant:1.7.0
║      ╙ org.apache.ant:ant-launcher:1.7.0
╟ org.yaml:snakeyaml:1.15
╙ org.beanshell:bsh:2.0b4

Finally, I’ve always been bugged by what I consider a glaring omission of the Gradle Android plug-in: not being able to run my applications. The plug-in generates tasks for the various variants of your application (assembleDevDebug, assembleDevRelease, installDevDebug, etc…) but strikingly, no "run" task. I’m happy to report that Kobalt’s Android plug-in supports exactly that. To see it in action, clone the Kobalt example and follow the instructions at the bottom of the README:

$ ./kobaltw runFreeDebug // build, install and launch that variant
$ ./kobaltw runFreeRelease // build, install and launch that variant

I’ve made a lot of improvements to the Android plug-in lately, but that will be the topic for another post.

The full series of articles on Kobalt can be found here.

The Kobalt diaries: annotation processing

I recently added apt support to Kobalt, which is a requirement for a build system these days, and something interesting happened.

First of all, the feature itself in Kobalt: pretty straightforward. The apt plug-in adds a new dependency directive similar to compile:

dependencies {
    apt("com.google.dagger:dagger:2.0.2")
}

The processing tool can be further configured (output directory, arguments, etc…) with a separate apt directive:

apt {
    outputDir = "generated/sources/apt"
}

In order to test this new feature, I decided to implement a simple annotation processor project and I went for a Version class generator. As I wrote this processor, I realized that it was actually something I could definitely use in my other projects.

Of course, you can always simply hard code the version number of your application in a source file but that version number is typically something that’s useful outside of your code: you might need it in your build file, or when you generate your artifacts, or maybe other projects need to refer to it. Therefore, it often makes sense to isolate that version number in a property file and have every entity that needs it read it from that property file.

This is how version-processor was born. It’s pretty simple really: all you need to do is annotate one of your classes with @Version and a GeneratedVersion.java file is created, which you can then refer to. That version number can either be hardcoded or specified in a properties file. Head over to the project’s main page for the details.

And of course, it’s built with Kobalt and if you are curious, here is the processor’s build file:

val processor = javaProject {
    name = "version-processor"
    group = "com.beust"
    artifactId = name
    version = "0.2"
    directory = "processor"

    assemble {
        mavenJars {}
    }

    jcenter {
        publish = true
    }
}

Happy version generating!

The full series of articles on Kobalt can be found here.

TensorFlow’s rough exterior

Like many others, I have paid very close attention to Google’s TensorFlow announcement and I’m planning to invest a decent amount of time to dive into it and understand it but watching Jeff Dean’s video about it, I couldn’t help but take notice of one of the code samples that he shows:

graph = tf.Graph()
with graph.AsDefault():
  examples = tf.constant(train_dataset)
  labels = tf.constants(train_labels)
  W = tf.Variables(tf.truncated_normal(rows*cols, num_labels]))
  b = tf.Variables(tf.zeros([num_labels]))

  logits = tf.mat_mul(examples, W) + b
  loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits, labels))

What a mess…

I realize this is just one of the two front ends (Python, the other being in C++) but the syntactic conventions of the snippet above are all over the map.

I see capitalized functions (Graph()) when most of the functions are lowercased. Capital variables (W) and lowercase ones (b), both of which the result of the same function. Functions using underscores and others using capitalized camel case. There just doesn’t seem to be any rhyme nor reason to the conventions.

The only style that’s not represented in this short snippet is straight camel case.

This hurts my eyes. Hopefully, spending some time with this fascinating tool will demystify it somewhat. Or maybe it will motivate me to write a front end I feel more comfortable with, say in Kotlin.

The Kobalt diaries: Android

A lot of work has gone into Kobalt since I announced its alpha:

I’m plannning to post more detailed updates as things progress but today, I’d like to briefly show a major milestone: the first Android APK generated by Kobalt.

I picked the Code path intro app as a test application. I first built it with Gradle to get a feel for it and the apk was generated in about 27 seconds. Then I generated a Build.kt file with ./kobaltw --init, added a few Android related directives to reach the following (complete) build file:

import com.beust.kobalt.*
import com.beust.kobalt.plugin.android.*
import com.beust.kobalt.plugin.java.*

val p = javaProject {
    name = "intro_android_demo"
    group = "com.example"
    artifactId = name
    version = "0.1"

    dependencies {
        compile("com.android.support:support-v4:aar:23.1",
                file("app/libs/android-async-http-1.4.3".jar))
    }

    sourceDirectories {
        listOf(path("app/src/main/java"))
    }

    android {
        applicationId = name
        buildToolsVersion = "21.1.2"
    }
}

Then I launched the build with ./kobaltw assemble, and…

Less than five seconds to generate R.java, compile it, compile the code, run aapt, generate classes.dex and finally, generated the apk. If you are curious, you can check out the full log.

Admittedly, Kobalt doesn’t yet handle build types and flavors nor manifest merging, but the example app I’m building here doesn’t use those either so I don’t expect the build time to increase much. There is a lot more to be done before Kobalt’s Android plug-in is ready for more users, but this is a pretty encouraging result.