diff --git a/README.md b/README.md
index 97447ea..f3f77c7 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,11 @@
+
+ |
+ |
+
+Bazel |
+Kotlin |
+
+
# Kotlin Rules for Bazel
[![Build Status](https://travis-ci.org/pubref/rules_kotlin.svg?branch=master)](https://travis-ci.org/pubref/rules_kotlin)
@@ -9,6 +17,7 @@ These rules are for building [Kotlin][kotlin] source with with
1. [kotlin_repositories](#kotlin_repositories)
1. [kotlin_library](#kotlin_library)
1. [kotlin_binary](#kotlin_binary)
+1. [kotlin_test](#kotlin_test)
## Workspace rules
@@ -18,7 +27,7 @@ Add the following to your `WORKSPACE` file:
git_repository(
name = "org_pubref_rules_kotlin",
remote = "https://github.com/pubref/rules_kotlin.git",
- tag = "v0.3.0", # update as needed
+ tag = "v0.3.1", # update as needed
)
load("@org_pubref_rules_kotlin//kotlin:rules.bzl", "kotlin_repositories")
@@ -40,7 +49,7 @@ dagger (used to build the `KotlinCompiler` bazel worker).
Add the following to your BUILD file:
```python
-load("@org_pubref_rules_kotlin//kotlin:rules.bzl", "kotlin_library", "kotlin_binary")
+load("@org_pubref_rules_kotlin//kotlin:rules.bzl", "kotlin_library")
```
### kotlin_library
@@ -95,18 +104,18 @@ android_binary(
| `srcs` | `label_list` | Kotlin source files `*.kt` |
| `deps` | `label_list` | List of `kotlin_library` targets |
| `java_deps` | `label_list` | List of java provider targets (`java_library`, `java_import`, `...`) |
+| `android_deps` | `label_list` | List of android provider targets (`android_library`) |
| `jars` | `label_list` | List of jar file targets (`*.jar`) |
| `x_opts` | `string_list` | List of additional `-X` options to `kotlinc` |
| `plugin_opts` | `string_dict` | List of additional `-P` options to `kotlinc` |
-| `use_worker` | `boolean` | Assign to `False` to disable the use of [bazel workers](https://bazel.build/blog/2015/12/10/java-workers.html). |
### kotlin_binary
-A `kotlin_binary` rule takes the same arguments as a `kotlin_library`,
-plus a required `main_class` argument (the name of the compiled kotlin
-class to run, in java package notation). This class should have a
-`fun main(...)` entrypoint. Example:
+A `kotlin_binary` macro takes the same arguments as a
+`kotlin_library`, plus a required `main_class` argument (the name of
+the compiled kotlin class to run, in java package notation). This
+class should have a `fun main(...)` entrypoint. Example:
```python
kotlin_binary(
@@ -128,6 +137,8 @@ Target :main_kt_deploy.jar up-to-date:
$ java -jar ./bazel-bin/.../main_kt_deploy.jar
```
+> The `kotlin-runtime.jar` is implicitly included by the `kotlin_binary` rule.
+
#### kotlin_binary attributes
Includes all `kotlin_library` attributes as well as:
@@ -137,15 +148,42 @@ Includes all `kotlin_library` attributes as well as:
| `main_class` | `string` | Main class to run with the `kotlin_binary` rule |
+### kotlin_test
+
+The `kotlin_test` rule is nearly identical the `kotlin_binary` rule
+(other than calling `java_test` internally rather than `java_binary`).
+
+
+```python
+kotlin_test(
+ name = "main_kt_test",
+ test_class = "examples.helloworld.MainKtTest",
+ srcs = ["MainKtTest.kt"],
+ size = "small",
+ deps = [
+ ":rules",
+ ],
+ java_deps = [
+ "@junit4//jar",
+ ],
+)
+```
+
+```sh
+$ bazel test :main_kt_test.jar
+```
+
+> The `kotlin-test.jar` is implicitly included by the `kotlin_test` rule.
+
### kotlin_compile
-The `kotlin_compile` rule runs the `kotlinc` tool to generate a `.jar`
-file from a list of kotlin source files. The `kotlin_library` rule
-(actually, macro) calls this internally and then makes the jarfile
-available to other java rules via a `java_import` rule.
+> TL;DR; You most likely do not need to interact with the
+> `kotlin_compile` rule directly.
-In summary, you most likely do not need to interact with the
-`kotlin_compile` rule directly.
+The `kotlin_compile` rule runs the kotlin compiler to generate a
+`.jar` file from a list of kotlin source files. The `kotlin_library`
+rule calls this internally and then makes the jarfile available to
+other java rules via a `java_import` rule.
# Summary
@@ -153,9 +191,9 @@ That's it! Hopefully these rules with make it easy to mix kotlin and
traditional java code in your projects and take advantage of bazel's
approach to fast, repeatable, and reliable builds.
-> Note: if you have a bunch of maven (central) dependencies, consider
-> [rules_maven](https://github.com/pubref/rules_maven) for taming the
-> issue of transitive dependencies with your java/kotlin projects.
+> Note: Consider [rules_maven](https://github.com/pubref/rules_maven)
+> for handling transitive maven dependencies with your java/kotlin
+> projects.
## Examples
@@ -167,13 +205,14 @@ $ cd rules_kotlin
$ bazel query //... --output label_kind
$ bazel run examples/helloworld:main_kt
$ bazel run examples/helloworld:main_java
+$ bazel test examples/helloworld:main_test
+$ bazel test examples/helloworld:main_kt_test
```
## TODO
-1. Implement a `kotlin_test` rule.
1. Proper `data` and runfiles support.
-2. Android support.
+2. Proper android support.
4. kapt support.
3. Incremental compilation.
diff --git a/examples/helloworld/BUILD b/examples/helloworld/BUILD
index 39e238e..b2a5788 100644
--- a/examples/helloworld/BUILD
+++ b/examples/helloworld/BUILD
@@ -1,6 +1,6 @@
package(default_visibility = ["//visibility:public"])
-load("//kotlin:rules.bzl", "kotlin_library", "kotlin_binary")
+load("//kotlin:rules.bzl", "kotlin_library", "kotlin_binary", "kotlin_test")
# A kotlin binary that depends on another kotlin rule (using kotlin
@@ -52,6 +52,20 @@ java_test(
]
)
+# A kotlin test rule that depends on a kotlin rule
+kotlin_test(
+ name = "main_kt_test",
+ test_class = "examples.helloworld.MainKtTest",
+ srcs = ["MainKtTest.kt"],
+ size = "small",
+ deps = [
+ ":rules",
+ ],
+ java_deps = [
+ "@junit4//jar",
+ ],
+)
+
# Included to test dependent java providers
java_library(
name = "guava",
diff --git a/examples/helloworld/MainKtTest.kt b/examples/helloworld/MainKtTest.kt
new file mode 100644
index 0000000..da7b57e
--- /dev/null
+++ b/examples/helloworld/MainKtTest.kt
@@ -0,0 +1,13 @@
+package examples.helloworld
+
+import kotlin.test.assertEquals
+import org.junit.Test
+
+public class MainKtTest {
+
+ @Test fun testRuleName(): Unit {
+ val rule = KotlinLibraryRule("foo", emptyList(), emptyList())
+ assertEquals("foo", rule.name)
+ }
+
+}
diff --git a/java/org/pubref/rules/kotlin/BUILD b/java/org/pubref/rules/kotlin/BUILD
index 61c7ae0..bfc2e52 100644
--- a/java/org/pubref/rules/kotlin/BUILD
+++ b/java/org/pubref/rules/kotlin/BUILD
@@ -7,6 +7,7 @@ java_binary(
visibility = ["//visibility:public"],
deps = [
":compiler",
+ ":preloader",
"//java/io/bazel/rules/closure:BazelWorker",
"//java/io/bazel/rules/closure/program",
"@com_google_dagger",
@@ -27,3 +28,16 @@ java_library(
"@com_github_jetbrains_kotlin//:compiler",
],
)
+
+java_library(
+ name = "preloader",
+ srcs = [
+ "KotlinPreloader.java",
+ ],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//java/io/bazel/rules/closure/program",
+ "@com_google_guava",
+ "@com_github_jetbrains_kotlin//:preloader",
+ ],
+)
diff --git a/java/org/pubref/rules/kotlin/KotlinPreloader.java b/java/org/pubref/rules/kotlin/KotlinPreloader.java
new file mode 100644
index 0000000..0f4e485
--- /dev/null
+++ b/java/org/pubref/rules/kotlin/KotlinPreloader.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 PubRef.org. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.pubref.rules.kotlin;
+
+import com.google.common.collect.Iterables;
+import io.bazel.rules.closure.program.CommandLineProgram;
+import org.jetbrains.kotlin.preloading.Preloader;
+
+/**
+ * CommandLineProgram Wrapper for the Kotlin Preloader.
+ */
+public final class KotlinPreloader implements CommandLineProgram {
+
+ @Override
+ public Integer apply(Iterable args) {
+ try {
+ Preloader.main(Iterables.toArray(args, String.class));
+ return 0;
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return 1;
+ }
+ }
+
+}
diff --git a/java/org/pubref/rules/kotlin/KotlinWorker.java b/java/org/pubref/rules/kotlin/KotlinWorker.java
index 90d92d9..b1feec2 100644
--- a/java/org/pubref/rules/kotlin/KotlinWorker.java
+++ b/java/org/pubref/rules/kotlin/KotlinWorker.java
@@ -50,6 +50,8 @@ public Integer apply(Iterable args) {
switch (head) {
case "KotlinCompiler":
return new KotlinCompiler().apply(tail);
+ case "KotlinPreloader":
+ return new KotlinPreloader().apply(tail);
default:
output.println(
"\nERROR: First flag to KotlinWorker should be specific compiler to run, "
diff --git a/kotlin/kotlin_repositories.bzl b/kotlin/kotlin_repositories.bzl
index 7a5aaf3..29ec198 100644
--- a/kotlin/kotlin_repositories.bzl
+++ b/kotlin/kotlin_repositories.bzl
@@ -10,10 +10,22 @@ java_import(
name = "runtime",
jars = ["lib/kotlin-runtime.jar"],
)
+java_import(
+ name = "stdlib",
+ jars = ["lib/kotlin-stdlib.jar"],
+)
java_import(
name = "compiler",
jars = ["lib/kotlin-compiler.jar"],
)
+java_import(
+ name = "preloader",
+ jars = ["lib/kotlin-preloader.jar"],
+)
+java_import(
+ name = "test",
+ jars = ["lib/kotlin-test.jar"],
+)
sh_binary(
name = "kotlin",
srcs = ["bin/kotlin"],
diff --git a/kotlin/rules.bzl b/kotlin/rules.bzl
index f151910..ad93ed0 100644
--- a/kotlin/rules.bzl
+++ b/kotlin/rules.bzl
@@ -7,7 +7,12 @@ load("//kotlin:kotlin_repositories.bzl", "kotlin_repositories")
def _kotlin_compile_impl(ctx):
kt_jar = ctx.outputs.kt_jar
inputs = []
- args = []
+
+ args = [
+ "KotlinPreloader",
+ "-cp", ctx.file._kotlin_compiler.path,
+ "org.jetbrains.kotlin.cli.jvm.K2JVMCompiler",
+ ]
# Single output jar
args += ["-d", kt_jar.path]
@@ -20,8 +25,12 @@ def _kotlin_compile_impl(ctx):
args += ["-P"]
args += ["plugin:%s=\"%s\"" % (k, v)]
- # Kotlin home - typically the dir 'external/com_github_jetbrains_kotlin'
- args += ["-kotlin-home", ctx.file._runtime.dirname + '/..']
+ # Kotlin home - typically the dir
+ # 'external/com_github_jetbrains_kotlin'
+ args += ["-kotlin-home", ctx.file._kotlin_compiler.dirname + '/..']
+ # Add all home libs to sandbox so they are discoverable by the
+ # preloader
+ inputs += ctx.files._kotlin_home
# Make classpath if needed. Include those from this and dependent rules.
jars = []
@@ -66,29 +75,16 @@ def _kotlin_compile_impl(ctx):
inputs += [file]
args += [file.path]
- # Add all home libs to sandbox
- inputs += ctx.files._kotlin_home
-
# Run the compiler
-
- if ctx.attr.use_worker:
- ctx.action(
- mnemonic = "KotlinCompile",
- inputs = inputs,
- outputs = [kt_jar],
- executable = ctx.executable._kotlinw,
- execution_requirements={"supports-workers": "1"},
- arguments = ['KotlinCompiler'] + args,
- progress_message="Compiling %d Kotlin source files to %s" % (len(ctx.files.srcs), ctx.outputs.kt_jar.short_path)
- )
- else:
- ctx.action(
- mnemonic = "KotlinCompile",
- inputs = inputs,
- outputs = [kt_jar],
- executable = ctx.executable._kotlinc,
- arguments = args,
- )
+ ctx.action(
+ mnemonic = "KotlinCompile",
+ inputs = inputs,
+ outputs = [kt_jar],
+ executable = ctx.executable._kotlinw,
+ execution_requirements = {"supports-workers": "1"},
+ arguments = args,
+ progress_message="Compiling %d Kotlin source files to %s" % (len(ctx.files.srcs), ctx.outputs.kt_jar.short_path)
+ )
return struct(
files = set([kt_jar]),
@@ -125,7 +121,7 @@ _kotlin_compile_attrs = {
providers = ["java"],
),
- # Dependent java rules.
+ # Dependent android rules.
"android_deps": attr.label_list(
providers = ["android"],
),
@@ -147,18 +143,17 @@ _kotlin_compile_attrs = {
# Plugin options
"plugin_opts": attr.string_dict(),
- # kotlin compiler (a shell script)
- "_kotlinc": attr.label(
- default=Label("@com_github_jetbrains_kotlin//:kotlinc"),
- executable = True,
- cfg = 'host',
- ),
-
# kotlin home (for runtime libraries discovery)
"_kotlin_home": attr.label(
default=Label("@com_github_jetbrains_kotlin//:home"),
),
+ # kotlin compiler jar
+ "_kotlin_compiler": attr.label(
+ default=Label("@com_github_jetbrains_kotlin//:compiler"),
+ single_file = True,
+ ),
+
# kotlin compiler worker (a java executable defined in this repo)
"_kotlinw": attr.label(
default=Label("//java/org/pubref/rules/kotlin:worker"),
@@ -166,17 +161,6 @@ _kotlin_compile_attrs = {
cfg = 'host',
),
- # kotlin runtime
- "_runtime": attr.label(
- default=Label("@com_github_jetbrains_kotlin//:runtime"),
- single_file = True,
- ),
-
- # Advanced options
- "use_worker": attr.bool(
- default = True,
- ),
-
}
@@ -215,7 +199,6 @@ def kotlin_binary(name,
jars = [],
srcs = [],
deps = [],
- use_worker = False,
x_opts = [],
plugin_opts = {},
java_deps = [],
@@ -227,7 +210,6 @@ def kotlin_binary(name,
java_deps = java_deps,
srcs = srcs,
deps = deps,
- use_worker = use_worker,
x_opts = x_opts,
plugin_opts = plugin_opts,
)
@@ -236,7 +218,36 @@ def kotlin_binary(name,
name = name,
runtime_deps = [
name + "_kt.jar",
- "@com_github_jetbrains_kotlin//:runtime",
- ] + java_deps,
+ ] + java_deps + [dep + "_kt" for dep in deps],
+ **kwargs
+ )
+
+
+def kotlin_test(name,
+ jars = [],
+ srcs = [],
+ deps = [],
+ x_opts = [],
+ plugin_opts = {},
+ java_deps = [],
+ **kwargs):
+
+ java_deps.append("@com_github_jetbrains_kotlin//:test")
+
+ kotlin_compile(
+ name = name + "_kt",
+ jars = jars,
+ java_deps = java_deps,
+ srcs = srcs,
+ deps = deps,
+ x_opts = x_opts,
+ plugin_opts = plugin_opts,
+ )
+
+ native.java_test(
+ name = name,
+ runtime_deps = [
+ name + "_kt.jar",
+ ] + java_deps + [dep + "_kt" for dep in deps],
**kwargs
)