# Ten minutes

Write and publish a Kobalt plug-in in ten minutes

## Introduction

In this example, we'll write a Kobalt plug-in that simply counts the number of source files and lines in your project. Starting from scratch, we'll have this plug-in published to JCenter and ready to use in ten minutes.

Let's start by creating our project:

    $ mkdir linecount
    $ cd linecount
    $ mkdir -p src/main/kotlin/com/beust/kobalt/plugin/linecount
    $ $KOBALT_HOME/kobaltw --init kotlin

`./kobaltw --init kotlin` creates an empty Kotlin project. Since we will be publishing this project to a Maven repository, we need to make sure that its `group`, `artifactId` and `version` are correct. The only thing that the generator can't guess is the `group`, so let's go ahead and fix it:

    val project = project {
        name = "kobalt-line-count"
        group = "com.beust.kobalt"
        artifactId = name
        version = "0.1"
        ...

We also need to add Kobalt as a dependency, so let's find out what the latest version of the jar file:

    $ ./kobaltw --resolve com.beust:kobalt:
    +======================================================================+
    |                           com.beust:kobalt:                          |
    |  https://jcenter.bintray.com/com/beust/kobalt/0.335/kobalt-0.335.jar |
    +======================================================================+

Note that the Maven id above doesn't specify a version (it ends with a colon), which means Kobalt will resolve it to the latest version it can find.Let's add this version in our dependencies:

        dependencies {
            compile("com.beust:kobalt:0.335")
        }

Next, we need to create our `kobalt-plugin.xml` file in the `src/main/resources/META-INF` directory. Once there, it will be automatically copied in the right place in our jar file:

    <kobalt-plugin>
        <name>kobalt-line-count</name>
        <plugin-actors>
            <class-name>com.beust.kobalt.plugin.linecount.LineCountPlugin</class-name>
        </plugin-actors>
    </kobalt-plugin>

Now we're ready to code.

Let's start by writing the simplest plug-in we can:

    package com.beust.kobalt.plugin.linecount

    import com.beust.kobalt.api.*

    public class Main : BasePlugin() {
        override val name = "kobalt-line-count"

        override fun apply(project: Project, context: KobaltContext) {
            println("*** Applying plugin $name with project $project")
        }
    }

Before we can upload it, we need to create the package in bintray, as explained here. Once this is done, we are ready to do our first upload:

    $ ./kobaltw uploadBintray
    ...
    ========== kobalt-line-count:uploadBintray
      Found 12 artifacts to upload:
        Uploading 12 / 12 |............|
    BUILD SUCCESSFUL (15 seconds)

If you go to the maven section of your bintray account, you will now see that the new package has two unpublished files. Your new plug-in won't be visible by clients until you publish those files, so let's update our build file to automatically publish files from now on:

    bintray {
        publish = true
    }

And now, let's implement our logic, which is pretty simple:

    // Main.kt
    @Task(name = "lineCount", description = "Count the lines", runBefore = arrayOf("compile"))
    fun lineCount(project: Project): TaskResult {
      var fileCount = 0
      var lineCount : Long = 0
      val matcher = FileSystems.getDefault().getPathMatcher("glob:**.kt")
      project.sourceDirectories.forEach {
        Files.walkFileTree(Paths.get(it), object: SimpleFileVisitor<Path>() {
          override public fun visitFile(path: Path, attrs: BasicFileAttributes): FileVisitResult {
            if (matcher.matches(path)) {
              fileCount++
              lineCount += Files.lines(path).count()
            }
            return FileVisitResult.CONTINUE
          }
        })
      }
      log(1, "Found $lineCount lines in $fileCount files")
      return TaskResult()
    }

We create a task called `"lineCount"` in which we look for all files ending in ".kt" in all the source directories of the project. Finally, we display a count of files and lines at the end by using `log()`, which is automatically supplied by the Kobalt API:

    public class Main : BasePlugin() {

Let's bump our version to 0.2 (since version 0.1 is already uploaded and Bintray won't allow us to overwrite it) and upload our new plug-in:

    $ ./kobaltw uploadBintray
    ...
    kobalt-line-count: Compilation succeeded
    ========== kobalt-line-count:assemble
    Created /Users/beust/kotlin/kobalt-line-count/kobaltBuild/libs/kobalt-line-count-0.2.jar
    ========== kobalt-line-count:generatePom
     Wrote /Users/beust/kotlin/kobalt-line-count/kobaltBuild/libs/kobalt-line-count-0.2.pom
    ========== kobalt-line-count:uploadBintray
      Found 12 artifacts to upload:
        Uploading 12 / 12 |............|
    BUILD SUCCESSFUL (15 seconds)

Finally, let's use our plug-in from another project. Since we didn't link this project to JCenter, it's uploaded in the user's maven repository, so we will have to add this maven repository to the build file where we want to use the plug-in. Adjust this line to point to your own maven repo:

    val repos = repos("https://dl.bintray.com/cbeust/maven/")
    val plugins = plugins("com.beust:kobalt-line-count:0.2")

Now let's launch a build:

    $ ./kobaltw assemble
    ...
    ========== kobalt:lineCount
    Found 4972 lines in 65 files
    ========== kobalt:compile
    ...

Note that our plugin ran before the `compile` task, as we requested in the `@Task` annotation. We can also verify that it's activated and we can invoke the task directly instead of having it run as part of the build:

    $ ./kobaltw --tasks
      ===== kobalt-line-count =====
        lineCount		Count the lines
    $ ./kobaltw lineCount
    Found 4972 lines in 65 files

And that's it! You can now iterate on your plug-in and upload it with additional `./kobaltw uploadBintray`. This plug-in is available on github. Note that the plug-in in the repo illustrates a few other concepts not discussed here, such as adding dynamic tasks, so I encourage you take a look at its source.

## Initialization

When your plug-in is activated, Kobalt will invoke its `apply()` function:

    override fun apply(project: Project, context: KobaltContext) {
    }

`project` is the project that your plug-in is currently being initialized for (keep in mind there can be multiple projects in a build) and the `context` gives you some information about other external data you might find useful, such as the command line that was passed to Kobalt.

## Debugging

The simplest way to run your plug-in in your IDE is to create a main function in the main class of your plug-in as follows:

    fun main(argv: Array<String>) {
        com.beust.kobalt.main(argv)
    }

    public class Main : BasePlugin() {
    // ...

Now you can simply create a launch configuration for your main class, which will invoke Kobalt.

The next step is to have Kobalt invoke your plug-in, so you will have to modify your build file to call it. As long as you haven't deployed your plug-in to Bintray, you might want to use the `file()` directive to declare your dependency, so that Kobalt will use the jar file on your file system:

    val p = plugins(
        file(homeDir("kotlin/kobalt-line-count/kobaltBuild/libs/kobalt-line-count-0.8.jar"))
    )

You can now set a breakpoint in your plug-in and launch the configuration you created above.