diff --git a/README.md b/README.md index 6aacf7b..18550dc 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ rules_clojure_setup() Differs from [simuons/rules_clojure](https://github.com/simuons/rules_clojure) that it uses `java_library` and `java_binary` as much as possible. -`clojure_binary`, `clojure_repl` and `clojure_test` are all macros that delegate to `java_binary`. `clojure_library` is new code. +`clojure_binary`, and `clojure_test` are macros that delegate to `java_binary`. `clojure_library` is new code. For fast compilation, `clojure_library` is a Bazel persistent worker. @@ -70,10 +70,14 @@ Note that AOT will determine whether a library should appear in `deps` or `runti ``` clojure_repl( name = "foo_repl", - deps = [":foo"]) + main_class = "clojure.main", + main_args = ["-e", "foo.main"], + runtime_deps = [":foo", "@deps//:__all"], + classpath_dirs = ["src", "dev", "test"], + data = []) ``` -Behaves as you'd expect. Delegates to `java_binary` with `main_class clojure.main`. +Like `java_binary`, the repl process runs from the bazel-bin package directory. Unlike the built-in java rules, it supports `classpath_dirs`, which allows adding directories to the classpath, like a conventional clojure repl. ### clojure_test diff --git a/rules.bzl b/rules.bzl index 4bbb5da..ee6f2f9 100644 --- a/rules.bzl +++ b/rules.bzl @@ -1,4 +1,5 @@ load("//rules:jar.bzl", _clojure_jar_impl = "clojure_jar_impl") +load("//rules:repl.bzl", _clojure_repl_impl = "clojure_repl_impl") clojure_library = rule( doc = "Define a clojure library", @@ -30,20 +31,19 @@ def clojure_binary(name, **kwargs): runtime_deps = deps + runtime_deps, **kwargs) -def clojure_repl(name, deps=[], ns=None, **kwargs): - args = [] - - if ns: - args.extend(["-e", """\"(require '[{ns}]) (in-ns '{ns})\"""".format(ns = ns)]) - - args.extend(["-e", "(clojure.main/repl)"]) - - native.java_binary(name=name, - runtime_deps=deps, - jvm_flags=["-Dclojure.main.report=stderr"], - main_class = "clojure.main", - args = args, - **kwargs) +clojure_repl = rule( + doc = "Define a clojure repl", + attrs = { + "main_class": attr.string(), + "runtime_deps": attr.label_list(default = [], providers = [[JavaInfo]]), + "classpath_dirs": attr.label_list(default = [], allow_files = True), + "data": attr.label_list(default = [], allow_files = True), + "jvm_flags": attr.string_list(default=[], doc = "Optional jvm_flags to pass to the repl binary"), + }, + executable = True, + provides = [], + toolchains = ["@bazel_tools//tools/jdk:toolchain_type"], + implementation = _clojure_repl_impl) def clojure_test(name, *, test_ns, deps=[], runtime_deps=[], **kwargs): # ideally the library name and the bin name would be the same. They can't be. diff --git a/rules/repl.bzl b/rules/repl.bzl new file mode 100644 index 0000000..60c6f2b --- /dev/null +++ b/rules/repl.bzl @@ -0,0 +1,36 @@ +### rule to start a clojure repl. We don't use `java_binary` because +### we want to support adding directories to the classpath (and in the +### future, possibly running from the source tree rather than `bazel-bin`), both in support of +### `clj` live reloading semantics + +def clojure_repl_impl(ctx): + + java_deps = depset(transitive = [d[JavaInfo].transitive_runtime_jars for d in ctx.attr.runtime_deps]) + + classpath_files = ["$BUILD_WORKSPACE_DIRECTORY/%s" % d.short_path for d in ctx.files.classpath_dirs] + + jars = [d.short_path for d in java_deps.to_list()] + + ## It's important that the dirs go ahead of jars, or live reloading breaks + classpath = classpath_files + jars + classpath_str = ":".join(classpath) + + sh_file = ctx.actions.declare_file(ctx.attr.name) + + runfiles = ctx.runfiles(files = ctx.files.data, + transitive_files = java_deps) + runfiles.merge_all([d[DefaultInfo].default_runfiles for d in ctx.attr.runtime_deps]) + + default_info = DefaultInfo(executable=sh_file, + runfiles = runfiles) + + cmd = """java {jvm_flags} -cp {cp} {main_class} {args}""".format(cp=classpath_str, + main_class = ctx.attr.main_class, + args = " ".join(ctx.attr.args), + jvm_flags = " ".join(ctx.attr.jvm_flags)) + + ctx.actions.write(output=sh_file, + content=cmd, + is_executable=True) + + return [ default_info ] diff --git a/src/rules_clojure/gen_build.clj b/src/rules_clojure/gen_build.clj index 86ecc14..be56e0b 100644 --- a/src/rules_clojure/gen_build.clj +++ b/src/rules_clojure/gen_build.clj @@ -868,10 +868,10 @@ (cond-> m (seq (:deps m)) (update :deps (comp vec distinct)) (:deps m) (update :deps (comp vec distinct)))))))))))))))))) - [(emit-bazel (list 'clojure_library (kwargs + [(emit-bazel (list 'java_library (kwargs {:name "__all" - :deps (->> jar->lib - (mapv (comp library->label val)))})))])) + :runtime_deps (->> jar->lib + (mapv (comp library->label val)))})))])) :encoding "UTF-8"))