├── .bazelignore ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── BUILD ├── LICENSE ├── README.md ├── WORKSPACE ├── docs └── rules.md ├── examples └── setup │ ├── custom │ ├── BUILD.bazel │ ├── WORKSPACE │ └── example.clj │ └── default │ ├── BUILD.bazel │ ├── WORKSPACE │ └── example.clj ├── repositories.bzl ├── rules.bzl ├── rules ├── BUILD ├── binary.bzl ├── compile.bzl ├── library.bzl ├── repl.bzl └── test.bzl ├── scripts ├── BUILD ├── compile.clj ├── library.clj └── test.clj ├── tests ├── BUILD ├── app-java-test.clj ├── app-test.clj ├── app.clj ├── assert │ ├── binary.sh │ ├── repl.sh │ └── test.sh ├── library-test.clj ├── library.clj ├── ns-to-file-path.clj ├── transitive │ ├── BUILD │ ├── app.clj │ ├── greeter │ │ ├── BUILD │ │ ├── HelloJava.java │ │ └── hello.clj │ └── test.clj ├── unconditionally-failing-test.clj └── unconditionally-passing-test.clj └── toolchains.bzl /.bazelignore: -------------------------------------------------------------------------------- 1 | examples 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | verify: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | - name: Mount bazel cache 16 | uses: actions/cache@v2 17 | with: 18 | path: ~/.cache/bazel 19 | key: bazel 20 | - name: Run bazel build 21 | run: bazel build //... 22 | - name: Run bazel test 23 | run: bazel test //... 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .ijwb/ 2 | bazel-* 3 | 4 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_clojure//:toolchains.bzl", "clojure_toolchain") 2 | 3 | toolchain_type( 4 | name = "toolchain", 5 | visibility = ["//visibility:public"], 6 | ) 7 | 8 | clojure_toolchain( 9 | name = "default_clojure_toolchain", 10 | classpath = [ 11 | "@org_clojure", 12 | "@org_clojure_spec_alpha", 13 | "@org_clojure_core_specs_alpha", 14 | ], 15 | ) 16 | 17 | toolchain( 18 | name = "clojure_toolchain", 19 | toolchain = ":default_clojure_toolchain", 20 | toolchain_type = "@rules_clojure//:toolchain", 21 | ) 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Clojure](https://clojure.org) rules for [Bazel](https://bazel.build) 2 | 3 |  4 | 5 | ## Setup 6 | 7 | Add the following to your `WORKSPACE`: 8 | 9 | ```skylark 10 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 11 | 12 | http_archive( 13 | name = "rules_clojure", 14 | sha256 = "c841fbf94af331f0f8f02de788ca9981d7c73a10cec798d3be0dd4f79d1d627d", 15 | strip_prefix = "rules_clojure-c044cb8608a2c3180cbfee89e66bbeb604afb146", 16 | urls = ["https://github.com/simuons/rules_clojure/archive/c044cb8608a2c3180cbfee89e66bbeb604afb146.tar.gz"], 17 | ) 18 | 19 | load("@rules_clojure//:repositories.bzl", "rules_clojure_dependencies", "rules_clojure_toolchains") 20 | 21 | rules_clojure_dependencies() 22 | 23 | rules_clojure_toolchains() 24 | ``` 25 | 26 | **Note**: Update commit and sha256 as needed. 27 | 28 | ## Rules 29 | 30 | Load rules in your `BUILD` files from [@rules_clojure//:rules.bzl](rules.bzl) 31 | 32 | - [clojure_binary](docs/rules.md#clojure_binary) 33 | - [clojure_java_library](docs/rules.md#clojure_java_library) 34 | - [clojure_library](docs/rules.md#clojure_library) 35 | - [clojure_repl](docs/rules.md#clojure_repl) 36 | - [clojure_test](docs/rules.md#clojure_test) 37 | 38 | ## Dependencies 39 | 40 | Rules require `clojure.jar` in implicit classpath via toolchains. 41 | 42 | Defaults are loaded with `rules_clojure_dependencies` from [@rules_clojure//:repositories.bzl](repositories.bzl) using `jvm_maven_import_external`. 43 | 44 | Please see [example](examples/setup/custom) of dependencies loaded with `rules_jvm_external`. 45 | 46 | ## Toolchains 47 | 48 | Rules require `@rules_clojure//:toolchain` type. 49 | 50 | Default is registered with `rules_clojure_toolchains` from [@rules_clojure//:repositories.bzl](repositories.bzl) 51 | 52 | Custom toolchain can be defined with `clojure_toolchain` rule from [@rules_clojure//:toolchains.bzl](toolchains.bzl) 53 | 54 | Please see [example](examples/setup/custom) of custom toolchain. 55 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "rules_clojure") 2 | 3 | load("//:repositories.bzl", "rules_clojure_dependencies", "rules_clojure_toolchains") 4 | 5 | rules_clojure_dependencies() 6 | 7 | rules_clojure_toolchains() 8 | -------------------------------------------------------------------------------- /docs/rules.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## clojure_binary 6 | 7 |
8 | clojure_binary(name, deps, main) 9 |10 | 11 | Builds a wrapper shell script with the same name as the rule. 12 | 13 | **ATTRIBUTES** 14 | 15 | 16 | | Name | Description | Type | Mandatory | Default | 17 | | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | 18 | | name | A unique name for this target. | Name | required | | 19 | | deps | Libraries to link into this binary. | List of labels | required | | 20 | | main | A namespace to find a -main function for execution. | String | required | | 21 | 22 | 23 | 24 | 25 | ## clojure_java_library 26 | 27 |
28 | clojure_java_library(name, deps, namespaces) 29 |30 | 31 | Compiles given namespaces to java. 32 | 33 | **ATTRIBUTES** 34 | 35 | 36 | | Name | Description | Type | Mandatory | Default | 37 | | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | 38 | | name | A unique name for this target. | Name | required | | 39 | | deps | Dependencies to compile. | List of labels | required | | 40 | | namespaces | Namespaces in classpath to compile. | List of strings | required | | 41 | 42 | 43 | 44 | 45 | ## clojure_library 46 | 47 |
48 | clojure_library(name, deps, srcs) 49 |50 | 51 | Builds a jar file from given sources with the paths corresponding to namespaces. 52 | 53 | **ATTRIBUTES** 54 | 55 | 56 | | Name | Description | Type | Mandatory | Default | 57 | | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | 58 | | name | A unique name for this target. | Name | required | | 59 | | deps | Libraries to link into this library. | List of labels | optional | [] | 60 | | srcs | clj source files. | List of labels | required | | 61 | 62 | 63 | 64 | 65 | ## clojure_repl 66 | 67 |
68 | clojure_repl(name, deps, ns) 69 |70 | 71 | Runs REPL with given dependencies in classpath. 72 | 73 | **ATTRIBUTES** 74 | 75 | 76 | | Name | Description | Type | Mandatory | Default | 77 | | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | 78 | | name | A unique name for this target. | Name | required | | 79 | | deps | Libraries available in REPL. | List of labels | optional | [] | 80 | | ns | Namespace to start REPL in. | String | optional | "" | 81 | 82 | 83 | 84 | 85 | ## clojure_test 86 | 87 |
88 | clojure_test(name, deps, srcs) 89 |90 | 91 | Runs clojure.test for given sources. 92 | 93 | **ATTRIBUTES** 94 | 95 | 96 | | Name | Description | Type | Mandatory | Default | 97 | | :-------------: | :-------------: | :-------------: | :-------------: | :-------------: | 98 | | name | A unique name for this target. | Name | required | | 99 | | deps | Libraries to link into this library. | List of labels | optional | [] | 100 | | srcs | clj source files with test cases. | List of labels | required | | 101 | 102 | 103 | -------------------------------------------------------------------------------- /examples/setup/custom/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_clojure//:rules.bzl", "clojure_library") 2 | load("@rules_clojure//:toolchains.bzl", "clojure_toolchain") 3 | 4 | clojure_toolchain( 5 | name = "custom_toolchain_def", 6 | classpath = [ 7 | "@maven//:org_clojure_clojure", 8 | "@maven//:org_clojure_core_specs_alpha", 9 | "@maven//:org_clojure_spec_alpha", 10 | ], 11 | ) 12 | 13 | toolchain( 14 | name = "custom_toolchain", 15 | toolchain = ":custom_toolchain_def", 16 | toolchain_type = "@rules_clojure//:toolchain", 17 | ) 18 | 19 | clojure_library( 20 | name = "example", 21 | srcs = ["example.clj"], 22 | ) 23 | -------------------------------------------------------------------------------- /examples/setup/custom/WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "custom") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 4 | 5 | http_archive( 6 | name = "rules_jvm_external", 7 | sha256 = "d85951a92c0908c80bd8551002d66cb23c3434409c814179c0ff026b53544dab", 8 | strip_prefix = "rules_jvm_external-3.3", 9 | url = "https://github.com/bazelbuild/rules_jvm_external/archive/3.3.zip", 10 | ) 11 | 12 | load("@rules_jvm_external//:defs.bzl", "maven_install") 13 | load("@rules_jvm_external//:specs.bzl", "maven") 14 | 15 | maven_install( 16 | artifacts = [ 17 | maven.artifact( 18 | "org.clojure", 19 | "clojure", 20 | "1.10.1", 21 | exclusions = [ 22 | "org.clojure:core.specs.alpha", 23 | "org.clojure:spec.alpha", 24 | ], 25 | ), 26 | maven.artifact( 27 | "org.clojure", 28 | "spec.alpha", 29 | "0.2.176", 30 | exclusions = [ 31 | "org.clojure:clojure", 32 | ], 33 | ), 34 | maven.artifact( 35 | "org.clojure", 36 | "core.specs.alpha", 37 | "0.2.44", 38 | exclusions = [ 39 | "org.clojure:clojure", 40 | ], 41 | ), 42 | ], 43 | repositories = [ 44 | "https://repo1.maven.org/maven2", 45 | "https://repo.clojars.org", 46 | ], 47 | ) 48 | 49 | local_repository( 50 | name = "rules_clojure", 51 | path = "../../..", 52 | ) 53 | 54 | register_toolchains("//:custom_toolchain") 55 | -------------------------------------------------------------------------------- /examples/setup/custom/example.clj: -------------------------------------------------------------------------------- 1 | (ns example) 2 | -------------------------------------------------------------------------------- /examples/setup/default/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_clojure//:rules.bzl", "clojure_library") 2 | 3 | clojure_library( 4 | name = "example", 5 | srcs = ["example.clj"], 6 | ) 7 | -------------------------------------------------------------------------------- /examples/setup/default/WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "default") 2 | 3 | local_repository( 4 | name = "rules_clojure", 5 | path = "../../..", 6 | ) 7 | 8 | load("@rules_clojure//:repositories.bzl", "rules_clojure_dependencies", "rules_clojure_toolchains") 9 | 10 | rules_clojure_dependencies() 11 | 12 | rules_clojure_toolchains() 13 | -------------------------------------------------------------------------------- /examples/setup/default/example.clj: -------------------------------------------------------------------------------- 1 | (ns example) 2 | -------------------------------------------------------------------------------- /repositories.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:jvm.bzl", "jvm_maven_import_external") 2 | 3 | def rules_clojure_dependencies(): 4 | jvm_maven_import_external( 5 | name = "org_clojure", 6 | artifact = "org.clojure:clojure:1.10.1", 7 | artifact_sha256 = "d4f6f991fd9ed2a59e7ea4779010b3b069a2b905f3463136c42201106b4ad21a", 8 | server_urls = ["https://repo1.maven.org/maven2/"], 9 | ) 10 | 11 | jvm_maven_import_external( 12 | name = "org_clojure_spec_alpha", 13 | artifact = "org.clojure:spec.alpha:0.2.176", 14 | artifact_sha256 = "fc4e96ecff34ddd2ab7fd050e74ae1379342ee09daa6028da52024c5de836cc4", 15 | server_urls = ["https://repo1.maven.org/maven2/"], 16 | ) 17 | 18 | jvm_maven_import_external( 19 | name = "org_clojure_core_specs_alpha", 20 | artifact = "org.clojure:core.specs.alpha:0.2.44", 21 | artifact_sha256 = "3b1ec4d6f0e8e41bf76842709083beb3b56adf3c82f9a4f174c3da74774b381c", 22 | server_urls = ["https://repo1.maven.org/maven2/"], 23 | ) 24 | 25 | def rules_clojure_toolchains(): 26 | native.register_toolchains("@rules_clojure//:clojure_toolchain") 27 | -------------------------------------------------------------------------------- /rules.bzl: -------------------------------------------------------------------------------- 1 | load("@rules_clojure//rules:binary.bzl", _clojure_binary_impl = "clojure_binary_impl") 2 | load("@rules_clojure//rules:compile.bzl", _clojure_java_library_impl = "clojure_java_library_impl") 3 | load("@rules_clojure//rules:library.bzl", _clojure_library_impl = "clojure_library_impl") 4 | load("@rules_clojure//rules:repl.bzl", _clojure_repl_impl = "clojure_repl_impl") 5 | load("@rules_clojure//rules:test.bzl", _clojure_test_impl = "clojure_test_impl") 6 | 7 | clojure_binary = rule( 8 | doc = "Builds a wrapper shell script with the same name as the rule.", 9 | attrs = { 10 | "main": attr.string(mandatory = True, doc = "A namespace to find a -main function for execution."), 11 | "deps": attr.label_list(mandatory = True, allow_empty = False, providers = [JavaInfo], doc = "Libraries to link into this binary."), 12 | }, 13 | executable = True, 14 | toolchains = ["@rules_clojure//:toolchain"], 15 | implementation = _clojure_binary_impl, 16 | ) 17 | 18 | clojure_java_library = rule( 19 | doc = "Compiles given namespaces to java.", 20 | attrs = { 21 | "namespaces": attr.string_list(mandatory = True, allow_empty = False, doc = "Namespaces in classpath to compile."), 22 | "deps": attr.label_list(mandatory = True, allow_empty = False, providers = [JavaInfo], doc = "Dependencies to compile."), 23 | }, 24 | provides = [JavaInfo], 25 | toolchains = ["@rules_clojure//:toolchain"], 26 | implementation = _clojure_java_library_impl, 27 | ) 28 | 29 | clojure_library = rule( 30 | doc = "Builds a jar file from given sources with the paths corresponding to namespaces.", 31 | attrs = { 32 | "srcs": attr.label_list(mandatory = True, allow_empty = False, allow_files = [".clj"], doc = "clj source files."), 33 | "deps": attr.label_list(default = [], providers = [JavaInfo], doc = "Libraries to link into this library."), 34 | }, 35 | provides = [JavaInfo], 36 | toolchains = ["@rules_clojure//:toolchain"], 37 | implementation = _clojure_library_impl, 38 | ) 39 | 40 | clojure_repl = rule( 41 | doc = "Runs REPL with given dependencies in classpath.", 42 | attrs = { 43 | "deps": attr.label_list(default = [], providers = [JavaInfo], doc = "Libraries available in REPL."), 44 | "ns": attr.string(mandatory = False, doc = "Namespace to start REPL in."), 45 | }, 46 | executable = True, 47 | toolchains = ["@rules_clojure//:toolchain"], 48 | implementation = _clojure_repl_impl, 49 | ) 50 | 51 | clojure_test = rule( 52 | doc = "Runs clojure.test for given sources.", 53 | attrs = { 54 | "srcs": attr.label_list(mandatory = True, allow_empty = False, allow_files = [".clj"], doc = "clj source files with test cases."), 55 | "deps": attr.label_list(default = [], providers = [JavaInfo], doc = "Libraries to link into this library."), 56 | }, 57 | test = True, 58 | toolchains = ["@rules_clojure//:toolchain"], 59 | implementation = _clojure_test_impl, 60 | ) 61 | -------------------------------------------------------------------------------- /rules/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simuons/rules_clojure/5605a9fb9653157579f7b86d9bd9b5993eec2b31/rules/BUILD -------------------------------------------------------------------------------- /rules/binary.bzl: -------------------------------------------------------------------------------- 1 | def clojure_binary_impl(ctx): 2 | toolchain = ctx.toolchains["@rules_clojure//:toolchain"] 3 | 4 | deps = depset( 5 | direct = toolchain.files.runtime, 6 | transitive = [dep[JavaInfo].transitive_runtime_deps for dep in ctx.attr.deps], 7 | ) 8 | 9 | ctx.actions.write( 10 | output = ctx.outputs.executable, 11 | content = "{java} -cp {classpath} clojure.main -m {main} $@".format( 12 | java = toolchain.java_runfiles, 13 | classpath = ":".join([f.short_path for f in deps.to_list()]), 14 | main = ctx.attr.main, 15 | ), 16 | ) 17 | 18 | return DefaultInfo( 19 | runfiles = ctx.runfiles( 20 | files = toolchain.files.scripts + toolchain.files.jdk, 21 | transitive_files = deps, 22 | ), 23 | ) 24 | -------------------------------------------------------------------------------- /rules/compile.bzl: -------------------------------------------------------------------------------- 1 | def clojure_java_library_impl(ctx): 2 | toolchain = ctx.toolchains["@rules_clojure//:toolchain"] 3 | 4 | classes = ctx.actions.declare_directory("%s.classes" % ctx.label.name) 5 | jar = ctx.actions.declare_file("%s.jar" % ctx.label.name) 6 | 7 | deps = depset( 8 | direct = toolchain.files.runtime, 9 | transitive = [dep[JavaInfo].transitive_runtime_deps for dep in ctx.attr.deps], 10 | ) 11 | 12 | cmd = """ 13 | set -e; 14 | rm -rf {classes} 15 | mkdir -p {classes} 16 | {java} -cp {classpath} -Dclojure.compile.path={classes} -Dclojure.compile.jar={jar} clojure.main {script} {namespaces} 17 | """.format( 18 | java = toolchain.java, 19 | classpath = ":".join([f.path for f in deps.to_list() + [classes]]), 20 | classes = classes.path, 21 | jar = jar.path, 22 | script = toolchain.scripts["compile.clj"].path, 23 | namespaces = " ".join(ctx.attr.namespaces), 24 | ) 25 | 26 | ctx.actions.run_shell( 27 | command = cmd, 28 | outputs = [classes, jar], 29 | inputs = deps.to_list() + toolchain.files.scripts + toolchain.files.jdk, 30 | mnemonic = "ClojureJavaLibrary", 31 | progress_message = "Compiling %s" % ctx.label, 32 | ) 33 | 34 | return [ 35 | DefaultInfo( 36 | files = depset([jar]), 37 | ), 38 | JavaInfo( 39 | output_jar = jar, 40 | compile_jar = jar, 41 | source_jar = None, 42 | deps = [dep[JavaInfo] for dep in toolchain.runtime + ctx.attr.deps], 43 | ), 44 | ] 45 | -------------------------------------------------------------------------------- /rules/library.bzl: -------------------------------------------------------------------------------- 1 | def clojure_library_impl(ctx): 2 | toolchain = ctx.toolchains["@rules_clojure//:toolchain"] 3 | 4 | jar = ctx.actions.declare_file("%s.jar" % ctx.label.name) 5 | 6 | cmd = "{java} -cp {classpath} -Dclojure.compile.jar={jar} clojure.main {script} {sources}".format( 7 | java = toolchain.java, 8 | classpath = ":".join([f.path for f in toolchain.files.runtime]), 9 | jar = jar.path, 10 | script = toolchain.scripts["library.clj"].path, 11 | sources = " ".join([f.path for f in ctx.files.srcs]), 12 | ) 13 | 14 | ctx.actions.run_shell( 15 | command = cmd, 16 | outputs = [jar], 17 | inputs = ctx.files.srcs + toolchain.files.runtime + toolchain.files.scripts + toolchain.files.jdk, 18 | mnemonic = "ClojureLibrary", 19 | progress_message = "Building %s" % ctx.label, 20 | ) 21 | 22 | return [ 23 | DefaultInfo( 24 | files = depset([jar]), 25 | ), 26 | JavaInfo( 27 | output_jar = jar, 28 | compile_jar = jar, 29 | source_jar = jar, 30 | deps = [dep[JavaInfo] for dep in ctx.attr.deps], 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /rules/repl.bzl: -------------------------------------------------------------------------------- 1 | def clojure_repl_impl(ctx): 2 | toolchain = ctx.toolchains["@rules_clojure//:toolchain"] 3 | 4 | deps = depset( 5 | direct = toolchain.files.runtime, 6 | transitive = [dep[JavaInfo].transitive_runtime_deps for dep in ctx.attr.deps], 7 | ) 8 | 9 | ctx.actions.write( 10 | output = ctx.outputs.executable, 11 | content = "{java} -cp {classpath} clojure.main {args}".format( 12 | java = toolchain.java_runfiles, 13 | classpath = ":".join([f.short_path for f in deps.to_list()]), 14 | args = " ".join(["-e", """\"(require '[{ns}]) (in-ns '{ns}) (clojure.main/repl)\"""".format(ns = ctx.attr.ns)] if ctx.attr.ns else []), 15 | ), 16 | ) 17 | 18 | return DefaultInfo( 19 | runfiles = ctx.runfiles( 20 | files = toolchain.files.scripts + toolchain.files.jdk, 21 | transitive_files = deps, 22 | ), 23 | ) 24 | -------------------------------------------------------------------------------- /rules/test.bzl: -------------------------------------------------------------------------------- 1 | def clojure_test_impl(ctx): 2 | toolchain = ctx.toolchains["@rules_clojure//:toolchain"] 3 | 4 | deps = depset( 5 | direct = toolchain.files.runtime, 6 | transitive = [dep[JavaInfo].transitive_runtime_deps for dep in ctx.attr.deps], 7 | ) 8 | 9 | ctx.actions.write( 10 | output = ctx.outputs.executable, 11 | content = "{java} -cp {classpath} clojure.main {script} {sources}".format( 12 | java = toolchain.java_runfiles, 13 | classpath = ":".join([f.short_path for f in deps.to_list()]), 14 | script = toolchain.scripts["test.clj"].path, 15 | sources = " ".join([f.path for f in ctx.files.srcs]), 16 | ), 17 | ) 18 | 19 | return DefaultInfo( 20 | runfiles = ctx.runfiles( 21 | files = ctx.files.srcs + toolchain.files.scripts + toolchain.files.jdk, 22 | transitive_files = deps, 23 | ), 24 | ) 25 | -------------------------------------------------------------------------------- /scripts/BUILD: -------------------------------------------------------------------------------- 1 | filegroup( 2 | name = "scripts", 3 | srcs = glob(["*.clj"]), 4 | visibility = ["//visibility:public"], 5 | ) 6 | -------------------------------------------------------------------------------- /scripts/compile.clj: -------------------------------------------------------------------------------- 1 | (require '[clojure.java.io :as io]) 2 | (import (java.io BufferedOutputStream FileOutputStream)) 3 | (import (java.util.jar Manifest JarEntry JarFile JarOutputStream)) 4 | 5 | (def compile-dir (-> "clojure.compile.path" System/getProperty io/file)) 6 | (def compile-jar (-> "clojure.compile.jar" System/getProperty io/file)) 7 | 8 | (def namespaces (map symbol *command-line-args*)) 9 | 10 | (doseq [namespace namespaces] 11 | (compile namespace)) 12 | 13 | (def manifest 14 | (let [m (Manifest.)] 15 | (doto (.getMainAttributes m) 16 | (.putValue "Manifest-Version" "1.0")) 17 | m)) 18 | 19 | (defn put-next-entry! [target name] 20 | (.putNextEntry target (doto (JarEntry. name) (.setTime 0)))) 21 | 22 | (with-open [jar-os (-> compile-jar FileOutputStream. BufferedOutputStream. JarOutputStream.)] 23 | (put-next-entry! jar-os JarFile/MANIFEST_NAME) 24 | (.write manifest jar-os) 25 | (.closeEntry jar-os) 26 | (doseq [file (file-seq compile-dir) 27 | :when (.isFile file) 28 | :let [name (.replaceFirst (str file) (str compile-dir "/") "")]] 29 | (put-next-entry! jar-os name) 30 | (io/copy file jar-os) 31 | (.closeEntry jar-os))) 32 | -------------------------------------------------------------------------------- /scripts/library.clj: -------------------------------------------------------------------------------- 1 | (require '[clojure.java.io :as io]) 2 | (import (java.io PushbackReader BufferedOutputStream FileOutputStream)) 3 | (import (java.util.jar Manifest JarEntry JarFile JarOutputStream)) 4 | 5 | (defn ns-symbol [file] 6 | (with-open [reader (PushbackReader. (io/reader file))] 7 | (loop [form (read reader false ::done)] 8 | (if (and (list? form) (= 'ns (first form))) 9 | (second form) 10 | (when-not (= ::done form) (recur reader)))))) 11 | 12 | (defn ns-path [file] 13 | (-> file ns-symbol name (.replace \- \_) (.replace \. \/) (str ".clj"))) 14 | 15 | (def compile-jar (-> "clojure.compile.jar" System/getProperty io/file)) 16 | 17 | (def sources (map io/file *command-line-args*)) 18 | 19 | (def manifest 20 | (let [m (Manifest.)] 21 | (doto (.getMainAttributes m) 22 | (.putValue "Manifest-Version" "1.0")) 23 | m)) 24 | 25 | (defn put-next-entry! [target name] 26 | (.putNextEntry target (doto (JarEntry. name) (.setTime 0)))) 27 | 28 | (with-open [jar-os (-> compile-jar FileOutputStream. BufferedOutputStream. JarOutputStream.)] 29 | (put-next-entry! jar-os JarFile/MANIFEST_NAME) 30 | (.write manifest jar-os) 31 | (.closeEntry jar-os) 32 | (doseq [file sources] 33 | (put-next-entry! jar-os (ns-path file)) 34 | (io/copy file jar-os) 35 | (.closeEntry jar-os))) 36 | -------------------------------------------------------------------------------- /scripts/test.clj: -------------------------------------------------------------------------------- 1 | (require '[clojure.test :as test]) 2 | (require '[clojure.java.io :as io]) 3 | (import (java.io PushbackReader)) 4 | 5 | (defn ns-symbol [file] 6 | (with-open [reader (PushbackReader. (io/reader file))] 7 | (loop [form (read reader false ::done)] 8 | (if (and (list? form) (= 'ns (first form))) 9 | (second form) 10 | (when-not (= ::done form) (recur reader)))))) 11 | 12 | (defn ns-path [file] 13 | (-> file ns-symbol name (.replace \- \_) (.replace \. \/) (str ".clj"))) 14 | 15 | (def sources (map io/file *command-line-args*)) 16 | 17 | (doseq [source sources] 18 | (load-file (.getCanonicalPath source))) 19 | 20 | (let [{:keys [fail error]} (apply test/run-tests (map ns-symbol sources))] 21 | (if-not (= 0 fail error) (System/exit 1))) 22 | -------------------------------------------------------------------------------- /tests/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_clojure//:rules.bzl", "clojure_binary", "clojure_java_library", "clojure_library", "clojure_repl", "clojure_test") 2 | load("@rules_java//java:defs.bzl", "java_binary") 3 | 4 | clojure_test( 5 | name = "unconditionally-passing-test", 6 | size = "small", 7 | srcs = ["unconditionally-passing-test.clj"], 8 | ) 9 | 10 | sh_test( 11 | name = "unconditionally-passing-test-report", 12 | size = "small", 13 | srcs = ["assert/test.sh"], 14 | args = [ 15 | "$(location :unconditionally-passing-test)", 16 | """'Testing tests.unconditionally-passing-test'""", 17 | ], 18 | data = [":unconditionally-passing-test"], 19 | ) 20 | 21 | clojure_test( 22 | name = "unconditionally-failing-test", 23 | size = "small", 24 | srcs = ["unconditionally-failing-test.clj"], 25 | tags = ["manual"], 26 | ) 27 | 28 | sh_test( 29 | name = "unconditionally-failing-test-report", 30 | size = "small", 31 | srcs = ["assert/test.sh"], 32 | args = [ 33 | "$(location :unconditionally-failing-test)", 34 | """'FAIL in (must-fail)'""", 35 | ], 36 | data = [":unconditionally-failing-test"], 37 | ) 38 | 39 | clojure_repl( 40 | name = "repl", 41 | ) 42 | 43 | sh_test( 44 | name = "repl-test", 45 | size = "small", 46 | srcs = ["assert/repl.sh"], 47 | args = [ 48 | "$(location :repl)", 49 | """'(+ 2 2)'""", 50 | """'user=> 4'""", 51 | ], 52 | data = [":repl"], 53 | ) 54 | 55 | clojure_library( 56 | name = "ns-to-file-path", 57 | srcs = ["ns-to-file-path.clj"], 58 | ) 59 | 60 | clojure_repl( 61 | name = "ns-to-file-path-repl", 62 | deps = [":ns-to-file-path"], 63 | ) 64 | 65 | sh_test( 66 | name = "ns-to-file-path-repl-test", 67 | size = "small", 68 | srcs = ["assert/repl.sh"], 69 | args = [ 70 | "$(location :ns-to-file-path-repl)", 71 | """'(load "/does/not/match/file_path")\n(all-ns)'""", 72 | """'does.not.match.file-path'""", 73 | ], 74 | data = [":ns-to-file-path-repl"], 75 | ) 76 | 77 | clojure_library( 78 | name = "library", 79 | srcs = ["library.clj"], 80 | ) 81 | 82 | clojure_test( 83 | name = "library-test", 84 | size = "small", 85 | srcs = ["library-test.clj"], 86 | deps = [":library"], 87 | ) 88 | 89 | clojure_binary( 90 | name = "library-binary", 91 | main = "tests.library", 92 | deps = [":library"], 93 | ) 94 | 95 | sh_test( 96 | name = "library-binary-test", 97 | size = "small", 98 | srcs = ["assert/binary.sh"], 99 | args = [ 100 | "$(location :library-binary)", 101 | """input""", 102 | """'library main input'""", 103 | ], 104 | data = [":library-binary"], 105 | ) 106 | 107 | clojure_repl( 108 | name = "library-repl", 109 | ns = "tests.library", 110 | deps = [":library"], 111 | ) 112 | 113 | sh_test( 114 | name = "library-repl-test", 115 | size = "small", 116 | srcs = ["assert/repl.sh"], 117 | args = [ 118 | "$(location :library-repl)", 119 | """'(echo "message")'""", 120 | """'tests.library=> "library message"'""", 121 | ], 122 | data = [":library-repl"], 123 | ) 124 | 125 | clojure_library( 126 | name = "app-transitive", 127 | srcs = ["app.clj"], 128 | deps = [":library"], 129 | ) 130 | 131 | clojure_test( 132 | name = "app-transitive-test", 133 | size = "small", 134 | srcs = ["app-test.clj"], 135 | deps = [":app-transitive"], 136 | ) 137 | 138 | clojure_repl( 139 | name = "app-transitive-repl", 140 | ns = "tests.app", 141 | deps = [":app-transitive"], 142 | ) 143 | 144 | sh_test( 145 | name = "app-transitive-repl-test", 146 | size = "small", 147 | srcs = ["assert/repl.sh"], 148 | args = [ 149 | "$(location :app-transitive-repl)", 150 | """'(echo "message")'""", 151 | """'tests.app=> "app library message"'""", 152 | ], 153 | data = [":app-transitive-repl"], 154 | ) 155 | 156 | clojure_binary( 157 | name = "app-transitive-binary", 158 | main = "tests.app", 159 | deps = [":app-transitive"], 160 | ) 161 | 162 | sh_test( 163 | name = "app-transitive-binary-test", 164 | size = "small", 165 | srcs = ["assert/binary.sh"], 166 | args = [ 167 | "$(location :app-transitive-binary)", 168 | """input""", 169 | """'app main library input'""", 170 | ], 171 | data = [":app-transitive-binary"], 172 | ) 173 | 174 | clojure_library( 175 | name = "app-bundled", 176 | srcs = [ 177 | "app.clj", 178 | "library.clj", 179 | ], 180 | ) 181 | 182 | clojure_test( 183 | name = "app-bundled-test", 184 | size = "small", 185 | srcs = ["app-test.clj"], 186 | deps = [":app-bundled"], 187 | ) 188 | 189 | clojure_repl( 190 | name = "app-bundled-repl", 191 | ns = "tests.app", 192 | deps = [":app-bundled"], 193 | ) 194 | 195 | sh_test( 196 | name = "app-bundled-repl-test", 197 | size = "small", 198 | srcs = ["assert/repl.sh"], 199 | args = [ 200 | "$(location :app-bundled-repl)", 201 | """'(echo "message")'""", 202 | """'tests.app=> "app library message"'""", 203 | ], 204 | data = [":app-bundled-repl"], 205 | ) 206 | 207 | clojure_binary( 208 | name = "app-bundled-binary", 209 | main = "tests.app", 210 | deps = [":app-bundled"], 211 | ) 212 | 213 | sh_test( 214 | name = "app-bundled-binary-test", 215 | size = "small", 216 | srcs = ["assert/binary.sh"], 217 | args = [ 218 | "$(location :app-bundled-binary)", 219 | """input""", 220 | """'app main library input'""", 221 | ], 222 | data = [":app-bundled-binary"], 223 | ) 224 | 225 | # AOT with clojure_java_library 226 | # TODO: Move to aot package 227 | # TODO: Add tests for multiple namespaces and multiple dependencies 228 | # TODO: Do we need multiple namespaces and dependencies since clojure compiles everything transitively? 229 | 230 | clojure_java_library( 231 | name = "library-java", 232 | namespaces = ["tests.library"], 233 | deps = [":library"], 234 | ) 235 | 236 | java_binary( 237 | name = "library-java-binary", 238 | main_class = "tests.library", 239 | runtime_deps = [":library-java"], 240 | ) 241 | 242 | sh_test( 243 | name = "library-java-binary-test", 244 | size = "small", 245 | srcs = ["assert/binary.sh"], 246 | args = [ 247 | "$(location :library-java-binary)", 248 | """input""", 249 | """'library main input'""", 250 | ], 251 | data = [":library-java-binary"], 252 | ) 253 | 254 | clojure_java_library( 255 | name = "app-bundled-java", 256 | namespaces = ["tests.app"], 257 | deps = [":app-bundled"], 258 | ) 259 | 260 | clojure_test( 261 | name = "app-bundled-java-test", 262 | size = "small", 263 | srcs = ["app-java-test.clj"], 264 | deps = [":app-bundled-java"], 265 | ) 266 | 267 | java_binary( 268 | name = "app-bundled-java-binary", 269 | main_class = "aot.CompiledAppClass", 270 | runtime_deps = [":app-bundled-java"], 271 | ) 272 | 273 | sh_test( 274 | name = "app-bundled-java-binary-test", 275 | size = "small", 276 | srcs = ["assert/binary.sh"], 277 | args = [ 278 | "$(location :app-bundled-java-binary)", 279 | """input""", 280 | """'app main library input'""", 281 | ], 282 | data = [":app-bundled-java-binary"], 283 | ) 284 | 285 | clojure_java_library( 286 | name = "app-transitive-java", 287 | namespaces = ["tests.app"], 288 | deps = [":app-transitive"], 289 | ) 290 | 291 | clojure_test( 292 | name = "app-transitive-java-test", 293 | size = "small", 294 | srcs = ["app-java-test.clj"], 295 | deps = [":app-transitive-java"], 296 | ) 297 | 298 | java_binary( 299 | name = "app-transitive-java-binary", 300 | main_class = "aot.CompiledAppClass", 301 | runtime_deps = [":app-transitive-java"], 302 | ) 303 | 304 | sh_test( 305 | name = "app-transitive-java-binary-test", 306 | size = "small", 307 | srcs = ["assert/binary.sh"], 308 | args = [ 309 | "$(location :app-transitive-java-binary)", 310 | """input""", 311 | """'app main library input'""", 312 | ], 313 | data = [":app-transitive-java-binary"], 314 | ) 315 | -------------------------------------------------------------------------------- /tests/app-java-test.clj: -------------------------------------------------------------------------------- 1 | (ns tests.app-java-test 2 | (:import aot.CompiledAppClass) 3 | (:use clojure.test)) 4 | 5 | (deftest app-java 6 | (is (= (.getName CompiledAppClass) "aot.CompiledAppClass")) 7 | (is (= (.getSuperclass CompiledAppClass) java.lang.Object))) 8 | -------------------------------------------------------------------------------- /tests/app-test.clj: -------------------------------------------------------------------------------- 1 | (ns tests.app-test 2 | (:require [tests.app :as app]) 3 | (:use clojure.test)) 4 | 5 | (deftest app 6 | (is (= (app/echo "message") "app library message"))) 7 | -------------------------------------------------------------------------------- /tests/app.clj: -------------------------------------------------------------------------------- 1 | (ns tests.app 2 | (:gen-class :name aot.CompiledAppClass) 3 | (:require [tests.library :as lib]) 4 | (:use clojure.test)) 5 | 6 | (defn echo [message] (str "app " (lib/echo message))) 7 | 8 | (defn -main [& args] (println "app main" (lib/echo (apply str args)))) 9 | -------------------------------------------------------------------------------- /tests/assert/binary.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | OUTPUT=$($1 $2) 3 | if [[ "$OUTPUT" != "$3" ]]; then 4 | echo "$OUTPUT is not equal to $3" 5 | exit 1 6 | fi 7 | exit 0 8 | -------------------------------------------------------------------------------- /tests/assert/repl.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | OUTPUT=$(echo "$2" | $1) 3 | if ! grep -q "$3" <<< "$OUTPUT"; then 4 | echo "REPL output:" 5 | echo "$OUTPUT" 6 | echo "Does not contain:" 7 | echo "$3" 8 | exit 1 9 | fi 10 | exit 0 11 | -------------------------------------------------------------------------------- /tests/assert/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | OUTPUT=$($1) 3 | if ! grep -q "$2" <<< "$OUTPUT"; then 4 | echo "Test output:" 5 | echo "$OUTPUT" 6 | echo "Does not contain:" 7 | echo "$2" 8 | exit 1 9 | fi 10 | exit 0 11 | -------------------------------------------------------------------------------- /tests/library-test.clj: -------------------------------------------------------------------------------- 1 | (ns tests.library-test 2 | (:require [tests.library :as lib]) 3 | (:use clojure.test)) 4 | 5 | (deftest library 6 | (is (= (lib/echo "test")) "library test")) 7 | -------------------------------------------------------------------------------- /tests/library.clj: -------------------------------------------------------------------------------- 1 | (ns tests.library (:gen-class)) 2 | 3 | (defn echo [message] (str "library " message)) 4 | 5 | (defn -main [& args] (println "library main" (apply str args))) 6 | -------------------------------------------------------------------------------- /tests/ns-to-file-path.clj: -------------------------------------------------------------------------------- 1 | (ns does.not.match.file-path) 2 | -------------------------------------------------------------------------------- /tests/transitive/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_clojure//:rules.bzl", "clojure_library", "clojure_test") 2 | 3 | clojure_library( 4 | name = "app", 5 | srcs = ["app.clj"], 6 | deps = ["//tests/transitive/greeter"], 7 | ) 8 | 9 | clojure_test( 10 | name = "test", 11 | size = "small", 12 | srcs = ["test.clj"], 13 | deps = [":app"], 14 | ) 15 | -------------------------------------------------------------------------------- /tests/transitive/app.clj: -------------------------------------------------------------------------------- 1 | (ns tests.transitive.app 2 | (:require [tests.transitive.greeter.hello :as hello]) 3 | (:gen-class)) 4 | 5 | (defn greeting [subject message] 6 | (str (hello/greet subject) " " message)) 7 | 8 | (defn -main [& args] (println (apply greeting args))) 9 | -------------------------------------------------------------------------------- /tests/transitive/greeter/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | load("@rules_clojure//:rules.bzl", "clojure_library") 3 | 4 | java_library( 5 | name = "greeter_java", 6 | srcs = ["HelloJava.java"], 7 | ) 8 | 9 | clojure_library( 10 | name = "greeter", 11 | srcs = ["hello.clj"], 12 | visibility = ["//visibility:public"], 13 | deps = [":greeter_java"], 14 | ) 15 | -------------------------------------------------------------------------------- /tests/transitive/greeter/HelloJava.java: -------------------------------------------------------------------------------- 1 | package tests.transitive.greeter; 2 | 3 | public class HelloJava { 4 | public String greet(String subject) { 5 | return "Hello " + subject; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/transitive/greeter/hello.clj: -------------------------------------------------------------------------------- 1 | (ns tests.transitive.greeter.hello 2 | (:import (tests.transitive.greeter HelloJava))) 3 | 4 | (defn greet [subject] 5 | (.greet (HelloJava.) subject)) 6 | -------------------------------------------------------------------------------- /tests/transitive/test.clj: -------------------------------------------------------------------------------- 1 | (ns tests.transitive.test 2 | (:require [tests.transitive.app :as lib]) 3 | (:use clojure.test)) 4 | 5 | (deftest transitive_deps 6 | (is (= "Hello Clojure Rules" (lib/greeting "Clojure" "Rules")))) 7 | -------------------------------------------------------------------------------- /tests/unconditionally-failing-test.clj: -------------------------------------------------------------------------------- 1 | (ns tests.unconditionally-failing-test (:use clojure.test)) 2 | 3 | (deftest must-fail (is false)) 4 | -------------------------------------------------------------------------------- /tests/unconditionally-passing-test.clj: -------------------------------------------------------------------------------- 1 | (ns tests.unconditionally-passing-test (:use clojure.test)) 2 | 3 | (deftest must-pass (is true)) 4 | -------------------------------------------------------------------------------- /toolchains.bzl: -------------------------------------------------------------------------------- 1 | def _clojure_toolchain(ctx): 2 | return [platform_common.ToolchainInfo( 3 | runtime = ctx.attr.classpath, 4 | scripts = {s.basename: s for s in ctx.files._scripts}, 5 | jdk = ctx.attr._jdk, 6 | java = ctx.attr._jdk[java_common.JavaRuntimeInfo].java_executable_exec_path, 7 | java_runfiles = ctx.attr._jdk[java_common.JavaRuntimeInfo].java_executable_runfiles_path, 8 | files = struct( 9 | runtime = ctx.files.classpath, 10 | scripts = ctx.files._scripts, 11 | jdk = ctx.files._jdk, 12 | ), 13 | )] 14 | 15 | clojure_toolchain = rule( 16 | implementation = _clojure_toolchain, 17 | attrs = { 18 | "classpath": attr.label_list( 19 | doc = "List of JavaInfo dependencies which will be implictly added to library/repl/test/binary classpath. Must contain clojure.jar", 20 | providers = [JavaInfo], 21 | ), 22 | "_scripts": attr.label( 23 | default = "//scripts", 24 | ), 25 | "_jdk": attr.label( 26 | default = "@bazel_tools//tools/jdk:current_java_runtime", 27 | providers = [java_common.JavaRuntimeInfo], 28 | ), 29 | }, 30 | provides = [platform_common.ToolchainInfo], 31 | ) 32 | --------------------------------------------------------------------------------