Showing preview only (232K chars total). Download the full file or copy to clipboard to get everything.
Repository: clojure/tools.build
Branch: master
Commit: 9d9563416bb0
Files: 92
Total size: 208.7 KB
Directory structure:
gitextract_x3_0vtk6/
├── .clj-kondo/
│ └── config.edn
├── .github/
│ ├── PULL_REQUEST_TEMPLATE
│ └── workflows/
│ ├── build_docs.yml
│ ├── ci.yml
│ ├── release.yml
│ └── snapshot.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── deps.edn
├── docs/
│ ├── build.graffle
│ ├── clojure.tools.build.api.html
│ ├── css/
│ │ ├── default.css
│ │ └── highlight.css
│ ├── index.html
│ └── js/
│ └── page_effects.js
├── epl-v10.html
├── pom.xml
├── src/
│ ├── main/
│ │ └── clojure/
│ │ └── clojure/
│ │ └── tools/
│ │ └── build/
│ │ ├── api/
│ │ │ └── specs.clj
│ │ ├── api.clj
│ │ ├── tasks/
│ │ │ ├── compile_clj.clj
│ │ │ ├── copy.clj
│ │ │ ├── create_basis.clj
│ │ │ ├── install.clj
│ │ │ ├── jar.clj
│ │ │ ├── javac.clj
│ │ │ ├── process.clj
│ │ │ ├── uber.clj
│ │ │ ├── write_pom.clj
│ │ │ └── zip.clj
│ │ └── util/
│ │ ├── file.clj
│ │ ├── log.clj
│ │ └── zip.clj
│ └── test/
│ └── clojure/
│ └── clojure/
│ └── tools/
│ └── build/
│ ├── tasks/
│ │ ├── test_basis.clj
│ │ ├── test_compile_clj.clj
│ │ ├── test_copy.clj
│ │ ├── test_delete.clj
│ │ ├── test_install.clj
│ │ ├── test_jar.clj
│ │ ├── test_javac.clj
│ │ ├── test_pom.clj
│ │ ├── test_process.clj
│ │ ├── test_uber.clj
│ │ ├── test_write_file.clj
│ │ └── test_zip.clj
│ ├── test_project_root.clj
│ └── test_util.clj
└── test-data/
├── assert/
│ ├── deps.edn
│ └── src/
│ └── foo/
│ └── check_assert.clj
├── bad-zip/
│ ├── bad.jar
│ └── deps.edn
├── case-sensitive-collision/
│ ├── j1/
│ │ └── FOO
│ └── j2/
│ └── foo/
│ └── hi.txt
├── nses/
│ └── src/
│ ├── a.clj
│ ├── b.clj
│ ├── c.clj
│ └── d.clj
├── p1/
│ ├── deps.edn
│ ├── java/
│ │ └── foo/
│ │ ├── Demo1.java
│ │ └── Demo2.java
│ ├── resources/
│ │ └── data.edn
│ └── src/
│ └── foo/
│ └── bar.clj
├── p2/
│ ├── deps.edn
│ ├── pom.xml
│ ├── resources/
│ │ └── data.edn
│ └── src/
│ └── foo/
│ └── bar.clj
├── p3/
│ ├── deps.edn
│ ├── resources/
│ │ └── data.edn
│ └── src/
│ └── foo/
│ └── bar.clj
├── p4/
│ ├── deps.edn
│ ├── pom.xml
│ ├── resources/
│ │ └── data.edn
│ └── src/
│ └── foo/
│ └── bar.clj
├── reflecting/
│ ├── deps.edn
│ └── src/
│ └── foo/
│ └── bar.clj
└── uber-conflict/
├── j1/
│ ├── META-INF/
│ │ └── LICENSE.txt
│ ├── append.txt
│ ├── data_readers.clj
│ ├── data_readers.cljc
│ ├── ignore.txt
│ ├── my/
│ │ └── j1.txt
│ └── overwrite.txt
├── j2/
│ ├── META-INF/
│ │ └── LICENSE.txt
│ ├── append.txt
│ ├── data_readers.clj
│ ├── data_readers.cljc
│ ├── ignore.txt
│ ├── my/
│ │ └── j2.txt
│ └── overwrite.txt
└── j3/
└── META-INF/
└── LICENSE.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .clj-kondo/config.edn
================================================
{:skip-comments true
:linters
{:unused-binding {:level :off}
:cond-else {:level :off}
:refer-all {:level :off}}}
================================================
FILE: .github/PULL_REQUEST_TEMPLATE
================================================
Hi! Thanks for your interest in contributing to this project.
Clojure contrib projects do not use GitHub issues or pull requests, and
require a signed Contributor Agreement. If you would like to contribute,
please read more about the CA and sign that first (this can be done online).
Then go to this project's issue tracker in JIRA to create tickets, update
tickets, or submit patches. For help in creating tickets and patches,
please see:
- Signing the CA: https://clojure.org/community/contributing
- Creating Tickets: https://clojure.org/community/creating_tickets
- Developing Patches: https://clojure.org/community/developing_patches
- Contributing FAQ: https://clojure.org/community/contributing
================================================
FILE: .github/workflows/build_docs.yml
================================================
name: Build Docs
permissions:
contents: write
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: 8
distribution: 'temurin'
- name: Set up Clojure
uses: DeLaGuardo/setup-clojure@11.0
with:
cli: 'latest'
- name: Cache clojure dependencies
uses: actions/cache@v3
with:
path: |
~/.m2/repository
~/.gitlibs
key: cljdeps-${{ hashFiles('deps.edn') }}
restore-keys: cljdeps-
- name: Clone the repo
uses: actions/checkout@v4
- name: Install rlwrap
run: sudo apt-get install -y rlwrap
- name: Execute doc build
run: |
clj -X:docs
- name: Commit and push
run: |
git config --global user.name clojure-build
git config --global user.email "clojure-build@users.noreply.github.com"
git add -u -v
git commit -m "Action doc commit"
git push origin master
================================================
FILE: .github/workflows/ci.yml
================================================
name: Tests
permissions:
contents: read
on: [push]
jobs:
test:
strategy:
matrix:
java-version: ["11", "17", "21"]
os: [ubuntu-latest, macOS-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Prepare java
uses: actions/setup-java@v4
with:
distribution: "adopt"
java-version: ${{ matrix.java-version }}
- name: Setup Clojure
uses: DeLaGuardo/setup-clojure@13.1
with:
cli: latest
- name: Checkout
uses: actions/checkout@v4
- name: Run tests not Windows
if: ${{ matrix.os != 'windows-latest' }}
run: clojure -X:test
shell: bash
- name: Run tests on Windows
if: ${{ matrix.os == 'windows-latest' }}
run: clojure -X:test
shell: powershell
================================================
FILE: .github/workflows/release.yml
================================================
name: Release on demand
permissions:
contents: write
on:
workflow_dispatch:
inputs:
releaseVersion:
description: "Version to release"
required: true
snapshotVersion:
description: "Snapshot version after release"
required: true
jobs:
call-release:
uses: clojure/build.ci/.github/workflows/release.yml@master
with:
releaseVersion: ${{ github.event.inputs.releaseVersion }}
snapshotVersion: ${{ github.event.inputs.snapshotVersion }}
centralDeployServer: "s01"
secrets: inherit
================================================
FILE: .github/workflows/snapshot.yml
================================================
name: Snapshot on demand
permissions:
contents: read
on: [workflow_dispatch]
jobs:
call-snapshot:
uses: clojure/build.ci/.github/workflows/snapshot.yml@master
secrets: inherit
================================================
FILE: .gitignore
================================================
*.iml
.idea/
target/
.nrepl*
.cpcache
.lein*
.java-version
project.clj
out*
test-out
.clj-kondo/.cache
.vscode
.lsp
.calva/mcp-server/port
.portal/vs-code.edn
================================================
FILE: CHANGELOG.md
================================================
Changelog
===========
* v0.10.13 ae52edf on Mar 16, 2026
* Update to latest tools.deps
* v0.10.12 97c5562 on Jan 5, 2026
* Update parent pom and dep versions
* v0.10.11 c6c670a on Oct 28, 2025
* write-pom - TBUILD-41 - add :src-pom :none option
* v0.10.10 deedd62 on Jul 29, 2025
* compile-clj - TBUILD-46 Capture out and error if process is unsuccessful
* v0.10.9 e405aac on May 13, 2025
* write-pom - TBUILD-44 - build.properties file should use `SOURCE_DATE_EPOCH` if set for reproducible builds
* v0.10.8 2fdfd66 on Mar 25, 2025
* process - TBUILD-1 Fix blocked buffering when capturing large output
* v0.10.7 573711e on Feb 8, 2025
* write-pom - add warning if pom-data ignored because src-pom template exists
* Update deps to latest
* v0.10.6 52cf7d6 on Nov 22, 2024
* compile-clj - add stream control args for compilation so out and err can be captured
* java-command - remove assert that :basis is required (that is no longer true)
* v0.10.5 2a21b7a on July 12, 2024
* compile-clj - fix ordering of namespaces not included in topo sort
* v0.10.4 31388ff on Jun 8, 2024
* uber, jar, zip - TBUILD-42 Use buffered output streams everywhere
* v0.10.3 15ead66 on May 1, 2024
* compile-clj - add simple spec for :basis arg
* v0.10.1 5e3b8f3 on Apr 28, 2024
* Update deps to latest
* compile-clj - validate that basis is non-nil
* v0.10.0 3a2c484 on Mar 8, 2024
* Updated deps to latest tools.deps and Clojure 1.11.2
* v0.9.6 8e78bcc on Oct 6, 2023
* write-pom - add :pom-data to supply extra pom data when generating a new pom
* uber - fix exclusions and conflict handling when including local deps on windows
* v0.9.5 24f2894 on Aug 11, 2023
* java-command - TBUILD-14 Use :jvm-opts from aliases in basis, if provided
* Update to latest deps
* v0.9.4 76b78fe on Mar 6, 2023
* uber - exclude Emacs backup files from uberjar inclusion (useful with local/git deps)
* uber - improve error message when file in local or git lib can't be read
* write-pom - improve docstring
* Switch to tools.deps 0.17.1297
* v0.9.3 e537cd1 on Feb 1, 2023
* NO CHANGES - just moved Maven artifact to io.github.clojure groupId to match git dep
* v0.9.2 fe6b140 on Jan 17, 2023
* uber - fix from TBUILD-30 to close copied file streams
* v0.9.1 27ff8a4 on Jan 13, 2023
* uber - TBUILD-35 Fix error on exploding jar with / entry
* uber - TBUILD-30 Apply exclusions and conflict handlers for local and git libs
* v0.9.0 8c93e0c on Dec 22, 2022
* Add clojure.tools.build.api/with-project-root macro
* java-command, compile-clj - TBUILD-34 - Use Clojure CLI logic in finding Java executable
* Switch to tools.deps 0.16.1264
* v0.8.5 9c738da on Nov 14, 2022
* Add support for snapshot and release policies on :mvn/repos (see TDEPS-101)
* v0.8.4 8c3cd69 on Nov 3, 2022
* TBUILD-26 Released as a Maven artifact
* v0.8.3 0d20256 on Jun 28, 2022
* uber - TBUILD-32 - Preserve reader conditionals when merging data\_readers.cljc
* uber - TBUILD-33 - Adjust regex for data\_readers to omit .cljs
* Update to tools.deps.alpha 0.14.1212
* v0.8.2 ba1a2bf on May 6, 2022
* Update deps to latest
* v0.8.1 7d40500 on Mar 11, 2022
* compile-clj - TBUILD-29 - add support for setting bindings during compilation
* v0.8.0 e3e3532 on Feb 24, 2022
* compile-clj - always create classpath entries relative to `*project-root*`
* java-command - don't resolve classpath entries, leave them relative to `*project-root*`
* v0.7.7 1474ad6 on Feb 18, 2022
* compile-clj - TBUILD-27 - Fix bug in prior impl
* v0.7.6 3549b5f on Feb 18, 2022
* compile-clj - TBUILD-27 - Use basis as default src dirs
* Update to tools.deps.alpha 0.12.1148
* v0.7.5 34727f7 on Jan 5, 2022
* Update to tools.deps.alpha 0.12.1109
* v0.7.4 ac442da on Dec 23, 2021
* Update to tools.deps.alpha 0.12.1104
* v0.7.3 2699924 on Dec 22, 2021
* Update to tools.deps.alpha 0.12.1098 (fix occasional race condition in parallel load of S3TransporterFactory)
* v0.7.2 0361dde on Dec 13, 2021
* copy-dir - copy posix file permissions only when posix permissions are supported
* v0.7.1 13f0fec on Dec 12, 2021
* copy-dir - TBUILD-24 - retain file permissions when doing string replace
* v0.7.0 16eddbf on Dec 12, 2021
* write-pom - TBUILD-23 - specify explicit output path with :target
* Update to tools.namespace 1.2.0
* Update to tools.deps.alpha 0.12.1090
* v0.6.8 d79ae84 on Nov 26, 2021
* uber - fix service append regex
* v0.6.7 8cca4f4 on Nov 24, 2021
* git-process - remove debug output
* v0.6.6 4d41c26 on Nov 14, 2021
* install - fix use of deprecated local-repo default in install - thanks @borkdude!
* v0.6.5 a0c3ff6 on Nov 12, 2021
* git-process - NEW task to run an arbitrary git process and return the output
* git-rev-count - updated to use git-process, added :git-command attribute
* v0.6.4 ea76dff on Nov 12, 2021
* java-command - add control over using classpath file with :use-cp-file (default=:auto)
* compile-clj - can now accept java-command passthrough args :java-cmd, :java-opts, :use-cp-file
* v0.6.3 4a1b53a on Nov 8, 2021
* Update to tools.deps 0.12.1071
* v0.6.2 226fb52 on Oct 12, 2021
* Update to tools.deps 0.12.1053
* v0.6.1 515b334 on Oct 10, 2021
* copy-dir - update attribute name added in v0.6.0
* v0.6.0 b139316 on Oct 10, 2021
* compile-clj - TBUILD-20 - fix regression with including class dir on classpath
* copy-dir - add option to copy but not replace in binary files by extension
* v0.5.1 21da7d4 on Sep 21, 2021
* Update to latest tools.deps 0.12.1048
* v0.5.0 7d77952 on Sep 16, 2021
* create-basis - do not include user deps.edn by default
* v0.4.1 452db44 on Sep 16, 2021
* Add some param spec checking
* v0.4.0 801a22f on Sep 15, 2021
* uber - TBUILD-2 - add support for configurable conflict handlers
* uber - TBUILD-11 - detect file and dir with same name in uber
* uber - TBUILD-16 - expand default exclusions
* uber - add support for custom exclusions
* v0.3.0 e418fc9 on Sep 11, 2021
* Bump to latest tools.deps - 0.12.1036
* v0.2.2 3049217 on Sep 7, 2021
* unzip - new task to unzip a zip file in a dir
* v0.2.1 dd64636 on Sep 4, 2021
* jar, uber - replace - with _ in main class name
* v0.2.0 7cbb94b on Aug 31, 2021
* compile-clj - fix docs and code to not require :src-dirs
* compile-clj - TBUILD-7 - sort namespaces using topological sort by default
* v0.1.9 6736c83 on Aug 22, 2021
* git-count-revs - add :path option
* pom-path - new task that computes the path to the pom.xml in a jar
* v0.1.8 38d2780 on Aug 13, 2021
* write-file - TBUILD-15 - add :string option
* write-pom - TBUILD-13 - add :scm options to write scm properties
* v0.1.7 8a3abc2 on July 28, 2021
* TBUILD-10 - fix missing assertions in tests
* Remove unnecessary resource file that overrides tools.deps
* v0.1.6 5636e61 on July 21, 2021
* copy-dir - Fix TBUILD-4 - set up default and overridable file ignore patterns
* v0.1.5 1cd59e6 on July 21, 2021
* jar, uber - Fix TBUILD-8 - jar files built on Windows had bad paths
* v0.1.4 169fef9 on July 20, 2021
* jar - add support for custom :manifest attributes
* uber - add support for custom :manifest attributes
* create-basis - make more tolerant of missing deps.edn file
* update tools.deps.alpha dependency to latest
* v0.1.3 660a71f on July 13, 2021
* write-pom - Fix TBUILD-3 - now takes deps from output of basis libs, so includes alias effects
* uber - exclude META-INF/\*.MF files
* v0.1.2 81f05b7 on July 9, 2021
* Update tools.deps.alpha dependency, public release
* v0.1.1 on July 7, 2021
* Add `java-command` take to create Java command line from basis
* v0.1.0 on July 5, 2021
* Renaming things towards release
================================================
FILE: CONTRIBUTING.md
================================================
This is a [Clojure contrib] project.
Under the Clojure contrib [guidelines], this project cannot accept
pull requests. All patches must be submitted via [JIRA].
See [Contributing] on the Clojure website for
more information on how to contribute.
[Clojure contrib]: https://clojure.org/community/contrib_libs
[Contributing]: https://clojure.org/community/contributing
[JIRA]: https://clojure.atlassian.net/browse/TBUILD
[guidelines]: https://clojure.org/community/contrib_howto
================================================
FILE: LICENSE
================================================
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial code and documentation
distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and are
distributed by that particular Contributor. A Contribution 'originates'
from a Contributor if it was added to the Program by such Contributor
itself or anyone acting on such Contributor's behalf. Contributions do not
include additions to the Program which: (i) are separate modules of
software distributed in conjunction with the Program under their own
license agreement, and (ii) are not derivative works of the Program.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents" mean patent claims licensable by a Contributor which are
necessarily infringed by the use or sale of its Contribution alone or when
combined with the Program.
"Program" means the Contributions distributed in accordance with this
Agreement.
"Recipient" means anyone who receives the Program under this Agreement,
including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide, royalty-free copyright license to
reproduce, prepare derivative works of, publicly display, publicly
perform, distribute and sublicense the Contribution of such Contributor,
if any, and such derivative works, in source code and object code form.
b) Subject to the terms of this Agreement, each Contributor hereby grants
Recipient a non-exclusive, worldwide, royalty-free patent license under
Licensed Patents to make, use, sell, offer to sell, import and otherwise
transfer the Contribution of such Contributor, if any, in source code and
object code form. This patent license shall apply to the combination of
the Contribution and the Program if, at the time the Contribution is
added by the Contributor, such addition of the Contribution causes such
combination to be covered by the Licensed Patents. The patent license
shall not apply to any other combinations which include the Contribution.
No hardware per se is licensed hereunder.
c) Recipient understands that although each Contributor grants the licenses
to its Contributions set forth herein, no assurances are provided by any
Contributor that the Program does not infringe the patent or other
intellectual property rights of any other entity. Each Contributor
disclaims any liability to Recipient for claims brought by any other
entity based on infringement of intellectual property rights or
otherwise. As a condition to exercising the rights and licenses granted
hereunder, each Recipient hereby assumes sole responsibility to secure
any other intellectual property rights needed, if any. For example, if a
third party patent license is required to allow Recipient to distribute
the Program, it is Recipient's responsibility to acquire that license
before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient
copyright rights in its Contribution, if any, to grant the copyright
license set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under
its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties
and conditions, express and implied, including warranties or
conditions of title and non-infringement, and implied warranties or
conditions of merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for
damages, including direct, indirect, special, incidental and
consequential damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are
offered by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such
Contributor, and informs licensees how to obtain it in a reasonable
manner on or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained
within the Program.
Each Contributor must identify itself as the originator of its Contribution,
if
any, in a manner that reasonably allows subsequent Recipients to identify the
originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities with
respect to end users, business partners and the like. While this license is
intended to facilitate the commercial use of the Program, the Contributor who
includes the Program in a commercial product offering should do so in a manner
which does not create potential liability for other Contributors. Therefore,
if a Contributor includes the Program in a commercial product offering, such
Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
every other Contributor ("Indemnified Contributor") against any losses,
damages and costs (collectively "Losses") arising from claims, lawsuits and
other legal actions brought by a third party against the Indemnified
Contributor to the extent caused by the acts or omissions of such Commercial
Contributor in connection with its distribution of the Program in a commercial
product offering. The obligations in this section do not apply to any claims
or Losses relating to any actual or alleged intellectual property
infringement. In order to qualify, an Indemnified Contributor must:
a) promptly notify the Commercial Contributor in writing of such claim, and
b) allow the Commercial Contributor to control, and cooperate with the
Commercial Contributor in, the defense and any related settlement
negotiations. The Indemnified Contributor may participate in any such claim at
its own expense.
For example, a Contributor might include the Program in a commercial product
offering, Product X. That Contributor is then a Commercial Contributor. If
that Commercial Contributor then makes performance claims, or offers
warranties related to Product X, those performance claims and warranties are
such Commercial Contributor's responsibility alone. Under this section, the
Commercial Contributor would have to defend claims against the other
Contributors related to those performance claims and warranties, and if a
court requires any other Contributor to pay any damages as a result, the
Commercial Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
Recipient is solely responsible for determining the appropriateness of using
and distributing the Program and assumes all risks associated with its
exercise of rights under this Agreement , including but not limited to the
risks and costs of program errors, compliance with applicable laws, damage to
or loss of data, programs or equipment, and unavailability or interruption of
operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of the
remainder of the terms of this Agreement, and without further action by the
parties hereto, such provision shall be reformed to the minimum extent
necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Program itself
(excluding combinations of the Program with other software or hardware)
infringes such Recipient's patent(s), then such Recipient's rights granted
under Section 2(b) shall terminate as of the date such litigation is filed.
All Recipient's rights under this Agreement shall terminate if it fails to
comply with any of the material terms or conditions of this Agreement and does
not cure such failure in a reasonable period of time after becoming aware of
such noncompliance. If all Recipient's rights under this Agreement terminate,
Recipient agrees to cease use and distribution of the Program as soon as
reasonably practicable. However, Recipient's obligations under this Agreement
and any licenses granted by Recipient relating to the Program shall continue
and survive.
Everyone is permitted to copy and distribute copies of this Agreement, but in
order to avoid inconsistency the Agreement is copyrighted and may only be
modified in the following manner. The Agreement Steward reserves the right to
publish new versions (including revisions) of this Agreement from time to
time. No one other than the Agreement Steward has the right to modify this
Agreement. The Eclipse Foundation is the initial Agreement Steward. The
Eclipse Foundation may assign the responsibility to serve as the Agreement
Steward to a suitable separate entity. Each new version of the Agreement will
be given a distinguishing version number. The Program (including
Contributions) may always be distributed subject to the version of the
Agreement under which it was received. In addition, after a new version of the
Agreement is published, Contributor may elect to distribute the Program
(including its Contributions) under the new version. Except as expressly
stated in Sections 2(a) and 2(b) above, Recipient receives no rights or
licenses to the intellectual property of any Contributor under this Agreement,
whether expressly, by implication, estoppel or otherwise. All rights in the
Program not expressly granted under this Agreement are reserved.
This Agreement is governed by the laws of the State of New York and the
intellectual property laws of the United States of America. No party to this
Agreement will bring a legal action under this Agreement more than one year
after the cause of action arose. Each party waives its rights to a jury trial in
any resulting litigation.
================================================
FILE: README.md
================================================
tools.build
========================================
A library for building artifacts in Clojure projects.
## Docs
* [API](https://clojure.github.io/tools.build)
* [Guide](https://clojure.org/guides/tools_build)
# Release Information
Latest release:
[deps.edn](https://clojure.org/reference/deps_and_cli) dependency information:
As a git dep:
```clojure
io.github.clojure/tools.build {:git/tag "v0.10.13" :git/sha "ae52edf"}
```
As a Maven dep:
```clojure
io.github.clojure/tools.build {:mvn/version "0.10.13"}
```
# Developer Information
[](https://github.com/clojure/tools.build/actions/workflows/ci.yml)
* [GitHub project](https://github.com/clojure/tools.build)
* [How to contribute](https://clojure.org/community/contributing)
* [Bug Tracker](https://clojure.atlassian.net/browse/TBUILD)
# Copyright and License
Copyright © Rich Hickey, Alex Miller, and contributors
All rights reserved. The use and
distribution terms for this software are covered by the
[Eclipse Public License 1.0] which can be found in the file
epl-v10.html at the root of this distribution. By using this software
in any fashion, you are agreeing to be bound by the terms of this
license. You must not remove this notice, or any other, from this
software.
[Eclipse Public License 1.0]: https://opensource.org/license/epl-1-0
================================================
FILE: deps.edn
================================================
{:paths ["src/main/clojure" "src/main/resources"]
:deps
{org.clojure/clojure {:mvn/version "1.12.4"}
org.clojure/tools.deps {:mvn/version "0.29.1598"}
;org.clojure/tools.deps {:git/url "https://github.com/clojure/tools.deps.git"
; :git/sha "459222ca6e4fce91cf5838435589a028cedbc784"}
org.clojure/tools.namespace {:mvn/version "1.5.1"}
org.slf4j/slf4j-nop {:mvn/version "1.7.36"}}
:aliases
{;; Run all tests
;; clj -X:test
:test {:extra-paths ["src/test/clojure"]
;;:extra-deps {io.github.cognitect-labs/test-runner
;; {:local/root "../test-runner"}}
:extra-deps {io.github.cognitect-labs/test-runner
{:git/url "https://github.com/cognitect-labs/test-runner.git"
:git/tag "v0.5.1" :git/sha "dfb30dd"}}
:exec-fn cognitect.test-runner.api/test
:exec-args {:dirs ["src/test/clojure"]
:patterns [".*"]}
:jvm-opts ["-XX:-OmitStackTraceInFastThrow"]}
;; Regenerate docs in docs/
;; clj -X:docs
:docs {:extra-deps {codox/codox {:mvn/version "0.10.8"}}
:exec-fn codox.main/generate-docs
:exec-args {:source-paths ["src/main/clojure"]
:namespaces [clojure.tools.build.api]
:output-path "docs"}}
;; Lint the source
;; clj -M:lint
:lint {:replace-deps {clj-kondo/clj-kondo {:mvn/version "2026.01.19"}}
:main-opts ["-m" "clj-kondo.main" "--lint" "src"]}
}
}
================================================
FILE: docs/clojure.tools.build.api.html
================================================
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>clojure.tools.build.api documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name"></span> <span class="project-version"></span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1 current"><a href="clojure.tools.build.api.html"><div class="inner"><span>clojure.tools.build.api</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="clojure.tools.build.api.html#var-*project-root*"><div class="inner"><span>*project-root*</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-compile-clj"><div class="inner"><span>compile-clj</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-copy-dir"><div class="inner"><span>copy-dir</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-copy-file"><div class="inner"><span>copy-file</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-create-basis"><div class="inner"><span>create-basis</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-delete"><div class="inner"><span>delete</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-git-count-revs"><div class="inner"><span>git-count-revs</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-git-process"><div class="inner"><span>git-process</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-install"><div class="inner"><span>install</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-jar"><div class="inner"><span>jar</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-java-command"><div class="inner"><span>java-command</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-javac"><div class="inner"><span>javac</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-pom-path"><div class="inner"><span>pom-path</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-process"><div class="inner"><span>process</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-resolve-path"><div class="inner"><span>resolve-path</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-set-project-root.21"><div class="inner"><span>set-project-root!</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-uber"><div class="inner"><span>uber</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-unzip"><div class="inner"><span>unzip</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-with-project-root"><div class="inner"><span>with-project-root</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-write-file"><div class="inner"><span>write-file</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-write-pom"><div class="inner"><span>write-pom</span></div></a></li><li class="depth-1"><a href="clojure.tools.build.api.html#var-zip"><div class="inner"><span>zip</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">clojure.tools.build.api</h1><div class="doc"><pre class="plaintext"></pre></div><div class="public anchor" id="var-*project-root*"><h3>*project-root*</h3><h4 class="dynamic">dynamic</h4><div class="usage"></div><div class="doc"><pre class="plaintext">Project root path, defaults to current directory.
Use `resolve-path` to resolve relative paths in terms of the *project-root*.
Use `set-project-root!` to override the default for all tasks.</pre></div></div><div class="public anchor" id="var-compile-clj"><h3>compile-clj</h3><div class="usage"><code>(compile-clj params)</code></div><div class="doc"><pre class="plaintext">Compile Clojure source to classes in :class-dir.
Clojure source files are found in :basis :paths by default, or override with :src-dirs.
Namespaces and order of compilation are one of:
* :ns-compile - compile these namespaces, in this order
* :sort - find all namespaces in source files and use either :topo (default)
or :bfs to order them for compilation
Options:
:basis - required, basis to use when compiling
:class-dir - required, dir to write classes, will be created if needed
:src-dirs - coll of Clojure source dirs, used to find all Clojure nses to compile
:ns-compile - coll of specific namespace symbols to compile
:sort - :topo (default) or :bfs for breadth-first search
:compile-opts - map of Clojure compiler options:
{:disable-locals-clearing false
:elide-meta [:doc :file :line ...]
:direct-linking false}
:bindings - map of Var to value to be set during compilation, for example:
{#'clojure.core/*assert* false
#'clojure.core/*warn-on-reflection* true}
:filter-nses - coll of symbols representing a namespace prefix to include
Additional options flow to the forked process doing the compile:
:java-cmd - Java command, default = $JAVA_CMD or 'java' on $PATH, or $JAVA_HOME/bin/java
:java-opts - coll of string jvm opts
:use-cp-file - one of:
:auto (default) - use only if os=windows && Java >= 9 && command length >= 8k
:always - always write classpath to temp file and include
:never - never write classpath to temp file (pass on command line)
:out - one of :inherit :capture :write :append :ignore
:err - one of :inherit :capture :write :append :ignore
:out-file - file path to write if :out is :write or :append
:err-file - file path to write if :err is :write or :append
Returns nil, or if needed a map with keys:
:out captured-out
:err captured-err</pre></div></div><div class="public anchor" id="var-copy-dir"><h3>copy-dir</h3><div class="usage"><code>(copy-dir params)</code></div><div class="doc"><pre class="plaintext">Copy the contents of the src-dirs to the target-dir, optionally do text replacement.
Returns nil.
Globs are wildcard patterns for specifying sets of files in a directory
tree, as specified in the glob syntax of java.nio.file.FileSystem:
<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)">https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)</a>
Options:
:target-dir - required, dir to write files, will be created if it doesn't exist
:src-dirs - required, coll of dirs to copy from
:include - glob of files to include, default = "**"
:ignores - collection of ignore regex patterns (applied only to file names),
see clojure.tools.build.tasks.copy/default-ignores for defaults
:replace - map of source to replacement string in files
:non-replaced-exts - coll of extensions to skip when replacing (still copied)
default = ["jpg" "jpeg" "png" "gif" "bmp"]</pre></div></div><div class="public anchor" id="var-copy-file"><h3>copy-file</h3><div class="usage"><code>(copy-file {:keys [src target], :as params})</code></div><div class="doc"><pre class="plaintext">Copy one file from source to target, creating target dirs if needed.
Returns nil.
Options:
:src - required, source path
:target - required, target path</pre></div></div><div class="public anchor" id="var-create-basis"><h3>create-basis</h3><div class="usage"><code>(create-basis)</code><code>(create-basis params)</code></div><div class="doc"><pre class="plaintext">Create a basis from a set of deps sources and a set of aliases. By default, use
root, user, and project deps and no aliases (essentially the same classpath you
get by default from the Clojure CLI).
Each dep source value can be :standard, a string path, a deps edn map, or nil.
Sources are merged in the order - :root, :user, :project, :extra.
Options (note, paths resolved via *project-root*):
:dir - directory root path, defaults to current directory
:root - dep source, default = :standard
:user - dep source, default = nil (for reproducibility, not included)
:project - dep source, default = :standard ("./deps.edn")
:extra - dep source, default = nil
:aliases - coll of aliases of argmaps to apply to subprocesses
Returns a runtime basis, which is the initial merged deps edn map plus these keys:
:resolve-args - the resolve args passed in, if any
:classpath-args - the classpath args passed in, if any
:libs - lib map, per resolve-deps
:classpath - classpath map per make-classpath-map
:classpath-roots - vector of paths in classpath order</pre></div></div><div class="public anchor" id="var-delete"><h3>delete</h3><div class="usage"><code>(delete {:keys [path], :as params})</code></div><div class="doc"><pre class="plaintext">Delete file or directory recursively, if it exists. Returns nil.
Options:
:path - required, path to file or directory</pre></div></div><div class="public anchor" id="var-git-count-revs"><h3>git-count-revs</h3><div class="usage"><code>(git-count-revs {:keys [dir git-command path], :or {git-command "git"}, :as params})</code></div><div class="doc"><pre class="plaintext">Shells out to git and returns count of commits on this branch:
git rev-list HEAD --count
Options:
:dir - dir to invoke this command from, default = current directory
:git-command - git command to use, default = "git"
:path - path to count commits for relative to dir</pre></div></div><div class="public anchor" id="var-git-process"><h3>git-process</h3><div class="usage"><code>(git-process params)</code></div><div class="doc"><pre class="plaintext">Run git process in the specified dir using git-command with git-args (which should not
start with "git"). git-args may either be a string (split on whitespace) or a vector
of strings. By default, stdout is captured, trimmed, and returned.
Options:
:dir - dir to invoke this command from, default = current directory
:git-command - git command to use, default = "git"
:git-args - required, coll of git-arg strings forming a command line OR
a string (do not use if args may have embedded spaces)
:capture - :out (default) or :err, else nothing
Examples:
(api/git-process {:git-args "rev-list HEAD --count"})
(api/git-process {:git-args "branch --show-current"})
(api/git-process {:git-args "rev-parse --short HEAD"})
(api/git-process {:git-args "push", :capture nil})</pre></div></div><div class="public anchor" id="var-install"><h3>install</h3><div class="usage"><code>(install params)</code></div><div class="doc"><pre class="plaintext">Install pom and jar to local Maven repo.
Returns nil.
Options:
:basis - required, used for :mvn/local-repo
:lib - required, lib symbol
:classifier - classifier string, if needed
:version - required, string version
:jar-file - required, path to jar file
:class-dir - required, used to find the pom file</pre></div></div><div class="public anchor" id="var-jar"><h3>jar</h3><div class="usage"><code>(jar params)</code></div><div class="doc"><pre class="plaintext">Create jar file containing contents of class-dir. Use main in the manifest
if provided. Returns nil.
Options:
:class-dir - required, dir to include in jar
:jar-file - required, jar to write
:main - main class symbol
:manifest - map of manifest attributes, merged last over defaults+:main</pre></div></div><div class="public anchor" id="var-java-command"><h3>java-command</h3><div class="usage"><code>(java-command params)</code></div><div class="doc"><pre class="plaintext">Create Java command line args. The classpath will be the combination of
:cp followed by the classpath from the basis, both are optional.
Note that 'java-command' will NOT resolve any relative paths from basis
or cp in terms of *project-root*, you will get a classpath with the same
relative paths. 'process' (if run with this output), will run in the
context of the *project-root* directory.
Options:
:java-cmd - Java command, default = $JAVA_CMD or 'java' on $PATH, or $JAVA_HOME/bin/java
:cp - coll of string classpath entries, used first (if provided)
:basis - runtime basis used for classpath and jvm opts from aliases, used last (if provided)
:java-opts - coll of string jvm opts
:main - required, main class symbol
:main-args - coll of main class args
:use-cp-file - one of:
:auto (default) - use only if os=windows && Java >= 9 && command length >= 8k
:always - always write classpath to temp file and include
:never - never write classpath to temp file (pass on command line)
Returns map suitable for passing to 'process' with keys:
:command-args - coll of command arg strings</pre></div></div><div class="public anchor" id="var-javac"><h3>javac</h3><div class="usage"><code>(javac params)</code></div><div class="doc"><pre class="plaintext">Compile Java source to classes. Returns nil.
Options:
:src-dirs - required, coll of Java source dirs
:class-dir - required, dir to write classes, will be created if needed
:basis - classpath basis to use when compiling
:javac-opts - coll of string opts, like ["-source" "8" "-target" "8"]</pre></div></div><div class="public anchor" id="var-pom-path"><h3>pom-path</h3><div class="usage"><code>(pom-path params)</code></div><div class="doc"><pre class="plaintext">Calculate path to pom.xml in jar meta (same path used by write-pom).
Relative path in jar is:
META-INF/maven/<groupId>/<artifactId>/pom.xml
If :class-dir provided, return path will start with resolved class-dir
(which may be either absolute or relative), otherwise just relative
path in jar.
Options:
:lib - required, used to form the relative path in jar to pom.xml
:class-dir - optional, if provided will be resolved and form the root of the path</pre></div></div><div class="public anchor" id="var-process"><h3>process</h3><div class="usage"><code>(process params)</code></div><div class="doc"><pre class="plaintext">Exec the command made from command-args, redirect out and err as directed,
and return {:exit exit-code, :out captured-out, :err captured-err}.
Options:
:command-args - required, coll of string args
:dir - directory to run the command from, default *project-root*
:out - one of :inherit :capture :write :append :ignore
:err - one of :inherit :capture :write :append :ignore
:out-file - file path to write if :out is :write or :append
:err-file - file path to write if :err is :write or :append
:env - map of environment variables to set
The :out and :err input flags take one of the following options:
:inherit - inherit the stream and write the subprocess io to this process's stream (default)
:capture - capture the stream to a string and return it
:write - write to :out-file or :err-file
:append - append to :out-file or :err-file
:ignore - ignore the stream</pre></div></div><div class="public anchor" id="var-resolve-path"><h3>resolve-path</h3><div class="usage"><code>(resolve-path path)</code></div><div class="doc"><pre class="plaintext">If path is absolute or root-path is nil then return path,
otherwise resolve relative to *project-root*.</pre></div></div><div class="public anchor" id="var-set-project-root.21"><h3>set-project-root!</h3><div class="usage"><code>(set-project-root! root)</code></div><div class="doc"><pre class="plaintext">Set *project-root* dir (default is ".")
</pre></div></div><div class="public anchor" id="var-uber"><h3>uber</h3><div class="usage"><code>(uber params)</code></div><div class="doc"><pre class="plaintext">Create uberjar file. An uberjar is a self-contained jar file containing
both the project contents AND the contents of all dependencies.
The project contents are represented by the class-dir. Use other tasks to
put Clojure source, class files, a pom file, or other resources in the
class-dir. In particular, see the copy-dir, write-pom, compile-clj, and
javac tasks.
The dependencies are pulled from the basis. All transitive deps will be
included. Dependency jars are expanded for inclusion in the uberjar.
Use :exclude to exclude specific paths from the expanded deps. Use
conflict-handlers to handle conflicts that may occur if two dependency
jar files include a file at the same path. See below for more detail.
If a main class or manifest are provided, those are put in the uberjar
META-INF/MANIFEST.MF file. Providing a main allows the jar to be
invoked with java -jar.
Returns nil.
Options:
:uber-file - required, uber jar file to create
:class-dir - required, local class dir to include
:basis - used to pull dep jars
:main - main class symbol
:manifest - map of manifest attributes, merged last over defaults + :main
:exclude - coll of string patterns (regex) to exclude from deps
:conflict-handlers - map of string pattern (regex) to built-in handlers,
symbols to eval, or function instances
When combining jar files into an uber jar, multiple jars may contain a file
at the same path. The conflict handlers are a map of string regex pattern
to:
a keyword (to use a built-in handler) or
a symbol (to resolve and invoke) or
a function instance
The special key `:default` specifies the default behavior if not matched.
Conflict handler signature (fn [params]) => effect-map:
params:
:path - String, path in uber jar, matched by regex
:in - InputStream to incoming file (see stream->string if needed)
:existing - File, existing File at path
:lib - symbol, lib source for incoming conflict
:state - map, available for retaining state during uberjar process
Handler should return effect-map with optional keys:
:state - updated state map
:write - map of string path to map of :string (string) or
:stream (InputStream) to write and optional :append
flag. Omit if no files to write.
Available built-in conflict handlers:
:ignore - don't do anything (default)
:overwrite - overwrite (replaces prior file)
:append - append the file with a blank line separator
:append-dedupe - append the file but dedupe appended sections
:data-readers - merge data_readers.clj
:warn - print a warning
:error - throw an error
Default conflict handlers map:
{"^data_readers.clj[c]?$" :data-readers
"^META-INF/services/.*" :append
"(?i)^(META-INF/)?(COPYRIGHT|NOTICE|LICENSE)(\\.(txt|md))?$" :append-dedupe
:default :ignore}</pre></div></div><div class="public anchor" id="var-unzip"><h3>unzip</h3><div class="usage"><code>(unzip params)</code></div><div class="doc"><pre class="plaintext">Unzip zip file to target-dir. Returns nil.
Options:
:zip-file - required, zip file to unzip
:target-dir - required, directory to unzip in</pre></div></div><div class="public anchor" id="var-with-project-root"><h3>with-project-root</h3><h4 class="type">macro</h4><div class="usage"><code>(with-project-root path & forms)</code></div><div class="doc"><pre class="plaintext">Execute forms in a bound project path (string) other than the default (".")
</pre></div></div><div class="public anchor" id="var-write-file"><h3>write-file</h3><div class="usage"><code>(write-file {:keys [path content string opts], :as params})</code></div><div class="doc"><pre class="plaintext">Writes a file at path, will create parent dirs if needed. Returns nil.
File contents may be specified either with :content (for data, that
will be pr-str'ed) or with :string for the string to write. If
neither is specified, an empty file is created (like touch).
Options:
:path - required, file path
:content - val to write, will pr-str
:string - string to write
:opts - coll of writer opts like :append and :encoding (per clojure.java.io)</pre></div></div><div class="public anchor" id="var-write-pom"><h3>write-pom</h3><div class="usage"><code>(write-pom params)</code></div><div class="doc"><pre class="plaintext">Write pom.xml and pom.properties files to the class dir under
META-INF/maven/group-id/artifact-id/ (where Maven typically writes
these files), or to target (exactly one of :class-dir and :target must
be provided).
Optionally use :src-pom to provide a pom template (or a default will
be generated from the provided attributes). The pom deps, dirs, and
repos from the basis will replace those sections of the template. Note
that the :src-pom template is not validated and should contain required
elements such as modelVersion.
If a repos map is provided it supersedes the repos in the basis.
Returns nil.
Options:
:basis - required, used to pull deps, repos
:src-pom - source pom.xml to synchronize from, default = "./pom.xml"
may be :none to ignore any existing pom.xml file
:class-dir - root dir for writing pom files, created if needed
:target - file path to write pom if no :class-dir specified
:lib - required, project lib symbol
:version - required, project version
:scm - map of scm properties to write in pom
keys: :connection, :developerConnection, :tag, :url
See: <a href="https://maven.apache.org/pom.html#SCM">https://maven.apache.org/pom.html#SCM</a> for details
:src-dirs - coll of src dirs
:resource-dirs - coll of resource dirs
:repos - map of repo name to repo config, replaces repos from deps.edn
:pom-data - vector of hiccup-style extra pom top elements to include when
:src-pom is :none or the source pom.xml does not exist:
[[:licenses
[:license
[:name "Eclipse Public License 1.0"]
[:url "<a href="https://opensource.org/license/epl-1-0/"">https://opensource.org/license/epl-1-0/"</a>;]
[:distribution "repo"]]]
[:organization "Super Corp"]]
The pom-data MUST NOT include:
:modelVersion, :packaging, :groupId, :artifactId, :version, :name,
:deps, :repositories, :build, or :scm</pre></div></div><div class="public anchor" id="var-zip"><h3>zip</h3><div class="usage"><code>(zip params)</code></div><div class="doc"><pre class="plaintext">Create zip file containing contents of src dirs. Returns nil.
Options:
:src-dirs - required, coll of source directories to include in zip
:zip-file - required, zip file to create</pre></div></div></div></body></html>
================================================
FILE: docs/css/default.css
================================================
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 15px;
}
pre, code {
font-family: Monaco, DejaVu Sans Mono, Consolas, monospace;
font-size: 9pt;
margin: 15px 0;
}
h1 {
font-weight: normal;
font-size: 29px;
margin: 10px 0 2px 0;
padding: 0;
}
h2 {
font-weight: normal;
font-size: 25px;
}
h5.license {
margin: 9px 0 22px 0;
color: #555;
font-weight: normal;
font-size: 12px;
font-style: italic;
}
.document h1, .namespace-index h1 {
font-size: 32px;
margin-top: 12px;
}
#header, #content, .sidebar {
position: fixed;
}
#header {
top: 0;
left: 0;
right: 0;
height: 22px;
color: #f5f5f5;
padding: 5px 7px;
}
#content {
top: 32px;
right: 0;
bottom: 0;
overflow: auto;
background: #fff;
color: #333;
padding: 0 18px;
}
.sidebar {
position: fixed;
top: 32px;
bottom: 0;
overflow: auto;
}
.sidebar.primary {
background: #e2e2e2;
border-right: solid 1px #cccccc;
left: 0;
width: 250px;
}
.sidebar.secondary {
background: #f2f2f2;
border-right: solid 1px #d7d7d7;
left: 251px;
width: 200px;
}
#content.namespace-index, #content.document {
left: 251px;
}
#content.namespace-docs {
left: 452px;
}
#content.document {
padding-bottom: 10%;
}
#header {
background: #3f3f3f;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
z-index: 100;
}
#header h1 {
margin: 0;
padding: 0;
font-size: 18px;
font-weight: lighter;
text-shadow: -1px -1px 0px #333;
}
#header h1 .project-version {
font-weight: normal;
}
.project-version {
padding-left: 0.15em;
}
#header a, .sidebar a {
display: block;
text-decoration: none;
}
#header a {
color: #f5f5f5;
}
.sidebar a {
color: #333;
}
#header h2 {
float: right;
font-size: 9pt;
font-weight: normal;
margin: 4px 3px;
padding: 0;
color: #bbb;
}
#header h2 a {
display: inline;
}
.sidebar h3 {
margin: 0;
padding: 10px 13px 0 13px;
font-size: 19px;
font-weight: lighter;
}
.sidebar h3 a {
color: #444;
}
.sidebar h3.no-link {
color: #636363;
}
.sidebar ul {
padding: 7px 0 6px 0;
margin: 0;
}
.sidebar ul.index-link {
padding-bottom: 4px;
}
.sidebar li {
display: block;
vertical-align: middle;
}
.sidebar li a, .sidebar li .no-link {
border-left: 3px solid transparent;
padding: 0 10px;
white-space: nowrap;
}
.sidebar li .no-link {
display: block;
color: #777;
font-style: italic;
}
.sidebar li .inner {
display: inline-block;
padding-top: 7px;
height: 24px;
}
.sidebar li a, .sidebar li .tree {
height: 31px;
}
.depth-1 .inner { padding-left: 2px; }
.depth-2 .inner { padding-left: 6px; }
.depth-3 .inner { padding-left: 20px; }
.depth-4 .inner { padding-left: 34px; }
.depth-5 .inner { padding-left: 48px; }
.depth-6 .inner { padding-left: 62px; }
.sidebar li .tree {
display: block;
float: left;
position: relative;
top: -10px;
margin: 0 4px 0 0;
padding: 0;
}
.sidebar li.depth-1 .tree {
display: none;
}
.sidebar li .tree .top, .sidebar li .tree .bottom {
display: block;
margin: 0;
padding: 0;
width: 7px;
}
.sidebar li .tree .top {
border-left: 1px solid #aaa;
border-bottom: 1px solid #aaa;
height: 19px;
}
.sidebar li .tree .bottom {
height: 22px;
}
.sidebar li.branch .tree .bottom {
border-left: 1px solid #aaa;
}
.sidebar.primary li.current a {
border-left: 3px solid #a33;
color: #a33;
}
.sidebar.secondary li.current a {
border-left: 3px solid #33a;
color: #33a;
}
.namespace-index h2 {
margin: 30px 0 0 0;
}
.namespace-index h3 {
font-size: 16px;
font-weight: bold;
margin-bottom: 0;
}
.namespace-index .topics {
padding-left: 30px;
margin: 11px 0 0 0;
}
.namespace-index .topics li {
padding: 5px 0;
}
.namespace-docs h3 {
font-size: 18px;
font-weight: bold;
}
.public h3 {
margin: 0;
float: left;
}
.usage {
clear: both;
}
.public {
margin: 0;
border-top: 1px solid #e0e0e0;
padding-top: 14px;
padding-bottom: 6px;
}
.public:last-child {
margin-bottom: 20%;
}
.members .public:last-child {
margin-bottom: 0;
}
.members {
margin: 15px 0;
}
.members h4 {
color: #555;
font-weight: normal;
font-variant: small-caps;
margin: 0 0 5px 0;
}
.members .inner {
padding-top: 5px;
padding-left: 12px;
margin-top: 2px;
margin-left: 7px;
border-left: 1px solid #bbb;
}
#content .members .inner h3 {
font-size: 12pt;
}
.members .public {
border-top: none;
margin-top: 0;
padding-top: 6px;
padding-bottom: 0;
}
.members .public:first-child {
padding-top: 0;
}
h4.type,
h4.dynamic,
h4.added,
h4.deprecated {
float: left;
margin: 3px 10px 15px 0;
font-size: 15px;
font-weight: bold;
font-variant: small-caps;
}
.public h4.type,
.public h4.dynamic,
.public h4.added,
.public h4.deprecated {
font-size: 13px;
font-weight: bold;
margin: 3px 0 0 10px;
}
.members h4.type,
.members h4.added,
.members h4.deprecated {
margin-top: 1px;
}
h4.type {
color: #717171;
}
h4.dynamic {
color: #9933aa;
}
h4.added {
color: #508820;
}
h4.deprecated {
color: #880000;
}
.namespace {
margin-bottom: 30px;
}
.namespace:last-child {
margin-bottom: 10%;
}
.index {
padding: 0;
font-size: 80%;
margin: 15px 0;
line-height: 16px;
}
.index * {
display: inline;
}
.index p {
padding-right: 3px;
}
.index li {
padding-right: 5px;
}
.index ul {
padding-left: 0;
}
.type-sig {
clear: both;
color: #088;
}
.type-sig pre {
padding-top: 10px;
margin: 0;
}
.usage code {
display: block;
color: #008;
margin: 2px 0;
}
.usage code:first-child {
padding-top: 10px;
}
p {
margin: 15px 0;
}
.public p:first-child, .public pre.plaintext {
margin-top: 12px;
}
.doc {
margin: 0 0 26px 0;
clear: both;
}
.public .doc {
margin: 0;
}
.namespace-index .doc {
margin-bottom: 20px;
}
.namespace-index .namespace .doc {
margin-bottom: 10px;
}
.markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td {
line-height: 22px;
}
.markdown li {
padding: 2px 0;
}
.markdown h2 {
font-weight: normal;
font-size: 25px;
margin: 30px 0 10px 0;
}
.markdown h3 {
font-weight: normal;
font-size: 20px;
margin: 30px 0 0 0;
}
.markdown h4 {
font-size: 15px;
margin: 22px 0 -4px 0;
}
.doc, .public, .namespace .index {
max-width: 680px;
overflow-x: visible;
}
.markdown pre > code {
display: block;
padding: 10px;
}
.markdown pre > code, .src-link a {
border: 1px solid #e4e4e4;
border-radius: 2px;
}
.markdown code:not(.hljs), .src-link a {
background: #f6f6f6;
}
pre.deps {
display: inline-block;
margin: 0 10px;
border: 1px solid #e4e4e4;
border-radius: 2px;
padding: 10px;
background-color: #f6f6f6;
}
.markdown hr {
border-style: solid;
border-top: none;
color: #ccc;
}
.doc ul, .doc ol {
padding-left: 30px;
}
.doc table {
border-collapse: collapse;
margin: 0 10px;
}
.doc table td, .doc table th {
border: 1px solid #dddddd;
padding: 4px 6px;
}
.doc table th {
background: #f2f2f2;
}
.doc dl {
margin: 0 10px 20px 10px;
}
.doc dl dt {
font-weight: bold;
margin: 0;
padding: 3px 0;
border-bottom: 1px solid #ddd;
}
.doc dl dd {
padding: 5px 0;
margin: 0 0 5px 10px;
}
.doc abbr {
border-bottom: 1px dotted #333;
font-variant: none;
cursor: help;
}
.src-link {
margin-bottom: 15px;
}
.src-link a {
font-size: 70%;
padding: 1px 4px;
text-decoration: none;
color: #5555bb;
}
================================================
FILE: docs/css/highlight.css
================================================
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
}
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
================================================
FILE: docs/index.html
================================================
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title> </title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name"></span> <span class="project-version"></span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 current"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1 "><a href="clojure.tools.build.api.html"><div class="inner"><span>clojure.tools.build.api</span></div></a></li></ul></div><div class="namespace-index" id="content"><h1><span class="project-title"><span class="project-name"></span> <span class="project-version"></span></span></h1><h2>Namespaces</h2><div class="namespace"><h3><a href="clojure.tools.build.api.html">clojure.tools.build.api</a></h3><div class="doc"><pre class="plaintext"></pre></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="clojure.tools.build.api.html#var-*project-root*">*project-root*</a> </li><li> <a href="clojure.tools.build.api.html#var-compile-clj">compile-clj</a> </li><li> <a href="clojure.tools.build.api.html#var-copy-dir">copy-dir</a> </li><li> <a href="clojure.tools.build.api.html#var-copy-file">copy-file</a> </li><li> <a href="clojure.tools.build.api.html#var-create-basis">create-basis</a> </li><li> <a href="clojure.tools.build.api.html#var-delete">delete</a> </li><li> <a href="clojure.tools.build.api.html#var-git-count-revs">git-count-revs</a> </li><li> <a href="clojure.tools.build.api.html#var-git-process">git-process</a> </li><li> <a href="clojure.tools.build.api.html#var-install">install</a> </li><li> <a href="clojure.tools.build.api.html#var-jar">jar</a> </li><li> <a href="clojure.tools.build.api.html#var-java-command">java-command</a> </li><li> <a href="clojure.tools.build.api.html#var-javac">javac</a> </li><li> <a href="clojure.tools.build.api.html#var-pom-path">pom-path</a> </li><li> <a href="clojure.tools.build.api.html#var-process">process</a> </li><li> <a href="clojure.tools.build.api.html#var-resolve-path">resolve-path</a> </li><li> <a href="clojure.tools.build.api.html#var-set-project-root.21">set-project-root!</a> </li><li> <a href="clojure.tools.build.api.html#var-uber">uber</a> </li><li> <a href="clojure.tools.build.api.html#var-unzip">unzip</a> </li><li> <a href="clojure.tools.build.api.html#var-with-project-root">with-project-root</a> </li><li> <a href="clojure.tools.build.api.html#var-write-file">write-file</a> </li><li> <a href="clojure.tools.build.api.html#var-write-pom">write-pom</a> </li><li> <a href="clojure.tools.build.api.html#var-zip">zip</a> </li></ul></div></div></div></body></html>
================================================
FILE: docs/js/page_effects.js
================================================
function visibleInParent(element) {
var position = $(element).position().top
return position > -50 && position < ($(element).offsetParent().height() - 50)
}
function hasFragment(link, fragment) {
return $(link).attr("href").indexOf("#" + fragment) != -1
}
function findLinkByFragment(elements, fragment) {
return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
}
function scrollToCurrentVarLink(elements) {
var elements = $(elements);
var parent = elements.offsetParent();
if (elements.length == 0) return;
var top = elements.first().position().top;
var bottom = elements.last().position().top + elements.last().height();
if (top >= 0 && bottom <= parent.height()) return;
if (top < 0) {
parent.scrollTop(parent.scrollTop() + top);
}
else if (bottom > parent.height()) {
parent.scrollTop(parent.scrollTop() + bottom - parent.height());
}
}
function setCurrentVarLink() {
$('.secondary a').parent().removeClass('current')
$('.anchor').
filter(function(index) { return visibleInParent(this) }).
each(function(index, element) {
findLinkByFragment(".secondary a", element.id).
parent().
addClass('current')
});
scrollToCurrentVarLink('.secondary .current');
}
var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
function scrollPositionId(element) {
var directory = window.location.href.replace(/[^\/]+\.html$/, '')
return 'scroll::' + $(element).attr('id') + '::' + directory
}
function storeScrollPosition(element) {
if (!hasStorage) return;
localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
}
function recallScrollPosition(element) {
if (!hasStorage) return;
$(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
$(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
}
function persistScrollPosition(element) {
recallScrollPosition(element)
$(element).scroll(function() { storeScrollPosition(element) })
}
function sidebarContentWidth(element) {
var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
return Math.max.apply(Math, widths)
}
function calculateSize(width, snap, margin, minimum) {
if (width == 0) {
return 0
}
else {
return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
}
}
function resizeSidebars() {
var primaryWidth = sidebarContentWidth('.primary')
var secondaryWidth = 0
if ($('.secondary').length != 0) {
secondaryWidth = sidebarContentWidth('.secondary')
}
// snap to grid
primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
$('.primary').css('width', primaryWidth)
$('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
if (secondaryWidth > 0) {
$('#content').css('left', primaryWidth + secondaryWidth + 2)
}
else {
$('#content').css('left', primaryWidth + 1)
}
}
$(window).ready(resizeSidebars)
$(window).ready(setCurrentVarLink)
$(window).ready(function() { persistScrollPosition('.primary')})
$(window).ready(function() {
$('#content').scroll(setCurrentVarLink)
$(window).resize(setCurrentVarLink)
})
================================================
FILE: epl-v10.html
================================================
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Eclipse Public License - Version 1.0</title>
<style type="text/css">
body {
size: 8.5in 11.0in;
margin: 0.25in 0.5in 0.25in 0.5in;
tab-interval: 0.5in;
}
p {
margin-left: auto;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
p.list {
margin-left: 0.5in;
margin-top: 0.05em;
margin-bottom: 0.05em;
}
</style>
</head>
<body lang="EN-US">
<p align=center><b>Eclipse Public License - v 1.0</b></p>
<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
AGREEMENT.</p>
<p><b>1. DEFINITIONS</b></p>
<p>"Contribution" means:</p>
<p class="list">a) in the case of the initial Contributor, the initial
code and documentation distributed under this Agreement, and</p>
<p class="list">b) in the case of each subsequent Contributor:</p>
<p class="list">i) changes to the Program, and</p>
<p class="list">ii) additions to the Program;</p>
<p class="list">where such changes and/or additions to the Program
originate from and are distributed by that particular Contributor. A
Contribution 'originates' from a Contributor if it was added to the
Program by such Contributor itself or anyone acting on such
Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in
conjunction with the Program under their own license agreement, and (ii)
are not derivative works of the Program.</p>
<p>"Contributor" means any person or entity that distributes
the Program.</p>
<p>"Licensed Patents" mean patent claims licensable by a
Contributor which are necessarily infringed by the use or sale of its
Contribution alone or when combined with the Program.</p>
<p>"Program" means the Contributions distributed in accordance
with this Agreement.</p>
<p>"Recipient" means anyone who receives the Program under
this Agreement, including all Contributors.</p>
<p><b>2. GRANT OF RIGHTS</b></p>
<p class="list">a) Subject to the terms of this Agreement, each
Contributor hereby grants Recipient a non-exclusive, worldwide,
royalty-free copyright license to reproduce, prepare derivative works
of, publicly display, publicly perform, distribute and sublicense the
Contribution of such Contributor, if any, and such derivative works, in
source code and object code form.</p>
<p class="list">b) Subject to the terms of this Agreement, each
Contributor hereby grants Recipient a non-exclusive, worldwide,
royalty-free patent license under Licensed Patents to make, use, sell,
offer to sell, import and otherwise transfer the Contribution of such
Contributor, if any, in source code and object code form. This patent
license shall apply to the combination of the Contribution and the
Program if, at the time the Contribution is added by the Contributor,
such addition of the Contribution causes such combination to be covered
by the Licensed Patents. The patent license shall not apply to any other
combinations which include the Contribution. No hardware per se is
licensed hereunder.</p>
<p class="list">c) Recipient understands that although each Contributor
grants the licenses to its Contributions set forth herein, no assurances
are provided by any Contributor that the Program does not infringe the
patent or other intellectual property rights of any other entity. Each
Contributor disclaims any liability to Recipient for claims brought by
any other entity based on infringement of intellectual property rights
or otherwise. As a condition to exercising the rights and licenses
granted hereunder, each Recipient hereby assumes sole responsibility to
secure any other intellectual property rights needed, if any. For
example, if a third party patent license is required to allow Recipient
to distribute the Program, it is Recipient's responsibility to acquire
that license before distributing the Program.</p>
<p class="list">d) Each Contributor represents that to its knowledge it
has sufficient copyright rights in its Contribution, if any, to grant
the copyright license set forth in this Agreement.</p>
<p><b>3. REQUIREMENTS</b></p>
<p>A Contributor may choose to distribute the Program in object code
form under its own license agreement, provided that:</p>
<p class="list">a) it complies with the terms and conditions of this
Agreement; and</p>
<p class="list">b) its license agreement:</p>
<p class="list">i) effectively disclaims on behalf of all Contributors
all warranties and conditions, express and implied, including warranties
or conditions of title and non-infringement, and implied warranties or
conditions of merchantability and fitness for a particular purpose;</p>
<p class="list">ii) effectively excludes on behalf of all Contributors
all liability for damages, including direct, indirect, special,
incidental and consequential damages, such as lost profits;</p>
<p class="list">iii) states that any provisions which differ from this
Agreement are offered by that Contributor alone and not by any other
party; and</p>
<p class="list">iv) states that source code for the Program is available
from such Contributor, and informs licensees how to obtain it in a
reasonable manner on or through a medium customarily used for software
exchange.</p>
<p>When the Program is made available in source code form:</p>
<p class="list">a) it must be made available under this Agreement; and</p>
<p class="list">b) a copy of this Agreement must be included with each
copy of the Program.</p>
<p>Contributors may not remove or alter any copyright notices contained
within the Program.</p>
<p>Each Contributor must identify itself as the originator of its
Contribution, if any, in a manner that reasonably allows subsequent
Recipients to identify the originator of the Contribution.</p>
<p><b>4. COMMERCIAL DISTRIBUTION</b></p>
<p>Commercial distributors of software may accept certain
responsibilities with respect to end users, business partners and the
like. While this license is intended to facilitate the commercial use of
the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create
potential liability for other Contributors. Therefore, if a Contributor
includes the Program in a commercial product offering, such Contributor
("Commercial Contributor") hereby agrees to defend and
indemnify every other Contributor ("Indemnified Contributor")
against any losses, damages and costs (collectively "Losses")
arising from claims, lawsuits and other legal actions brought by a third
party against the Indemnified Contributor to the extent caused by the
acts or omissions of such Commercial Contributor in connection with its
distribution of the Program in a commercial product offering. The
obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In
order to qualify, an Indemnified Contributor must: a) promptly notify
the Commercial Contributor in writing of such claim, and b) allow the
Commercial Contributor to control, and cooperate with the Commercial
Contributor in, the defense and any related settlement negotiations. The
Indemnified Contributor may participate in any such claim at its own
expense.</p>
<p>For example, a Contributor might include the Program in a commercial
product offering, Product X. That Contributor is then a Commercial
Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance
claims and warranties are such Commercial Contributor's responsibility
alone. Under this section, the Commercial Contributor would have to
defend claims against the other Contributors related to those
performance claims and warranties, and if a court requires any other
Contributor to pay any damages as a result, the Commercial Contributor
must pay those damages.</p>
<p><b>5. NO WARRANTY</b></p>
<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
responsible for determining the appropriateness of using and
distributing the Program and assumes all risks associated with its
exercise of rights under this Agreement , including but not limited to
the risks and costs of program errors, compliance with applicable laws,
damage to or loss of data, programs or equipment, and unavailability or
interruption of operations.</p>
<p><b>6. DISCLAIMER OF LIABILITY</b></p>
<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>
<p><b>7. GENERAL</b></p>
<p>If any provision of this Agreement is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of
the remainder of the terms of this Agreement, and without further action
by the parties hereto, such provision shall be reformed to the minimum
extent necessary to make such provision valid and enforceable.</p>
<p>If Recipient institutes patent litigation against any entity
(including a cross-claim or counterclaim in a lawsuit) alleging that the
Program itself (excluding combinations of the Program with other
software or hardware) infringes such Recipient's patent(s), then such
Recipient's rights granted under Section 2(b) shall terminate as of the
date such litigation is filed.</p>
<p>All Recipient's rights under this Agreement shall terminate if it
fails to comply with any of the material terms or conditions of this
Agreement and does not cure such failure in a reasonable period of time
after becoming aware of such noncompliance. If all Recipient's rights
under this Agreement terminate, Recipient agrees to cease use and
distribution of the Program as soon as reasonably practicable. However,
Recipient's obligations under this Agreement and any licenses granted by
Recipient relating to the Program shall continue and survive.</p>
<p>Everyone is permitted to copy and distribute copies of this
Agreement, but in order to avoid inconsistency the Agreement is
copyrighted and may only be modified in the following manner. The
Agreement Steward reserves the right to publish new versions (including
revisions) of this Agreement from time to time. No one other than the
Agreement Steward has the right to modify this Agreement. The Eclipse
Foundation is the initial Agreement Steward. The Eclipse Foundation may
assign the responsibility to serve as the Agreement Steward to a
suitable separate entity. Each new version of the Agreement will be
given a distinguishing version number. The Program (including
Contributions) may always be distributed subject to the version of the
Agreement under which it was received. In addition, after a new version
of the Agreement is published, Contributor may elect to distribute the
Program (including its Contributions) under the new version. Except as
expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
rights or licenses to the intellectual property of any Contributor under
this Agreement, whether expressly, by implication, estoppel or
otherwise. All rights in the Program not expressly granted under this
Agreement are reserved.</p>
<p>This Agreement is governed by the laws of the State of New York and
the intellectual property laws of the United States of America. No party
to this Agreement will bring a legal action under this Agreement more
than one year after the cause of action arose. Each party waives its
rights to a jury trial in any resulting litigation.</p>
</body>
</html>
================================================
FILE: pom.xml
================================================
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.clojure</groupId>
<artifactId>tools.build</artifactId>
<version>0.10.14-SNAPSHOT</version>
<name>tools.build</name>
<description>Clojure builds as Clojure programs.</description>
<parent>
<groupId>org.clojure</groupId>
<artifactId>pom.contrib</artifactId>
<version>1.4.0</version>
</parent>
<developers>
<developer>
<id>puredanger</id>
<name>Alex Miller</name>
</developer>
</developers>
<properties>
<!-- used for build -->
<clojure.warnOnReflection>true</clojure.warnOnReflection>
<clojure.version>1.12.4</clojure.version>
</properties>
<dependencies>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>${clojure.version}</version>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>tools.deps</artifactId>
<version>0.29.1598</version>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>tools.namespace</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>
<!-- overrides parent pom to set repo to s01 (the "new" repo) -->
<distributionManagement>
<snapshotRepository>
<!-- This id is linked to the key setup on the CI server -->
<id>sonatype-nexus-staging</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<plugin>
<!-- By default, compile everything as a sanity check, but do
not include any AOT-compiled .class files in the
JAR. Projects may override as needed. -->
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
<version>1.7.1</version>
<extensions>true</extensions>
<configuration>
<warnOnReflection>${clojure.warnOnReflection}</warnOnReflection>
<temporaryOutputDirectory>true</temporaryOutputDirectory>
</configuration>
<executions>
<execution>
<id>clojure-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>clojure-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- overrides parent pom because new projects are going to different staging repo - s01 -->
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.7.0</version>
<extensions>true</extensions>
<configuration>
<!-- The server "id" element from settings to use authentication from -->
<serverId>sonatype-nexus-staging</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
</build>
<scm>
<connection>scm:git:git@github.com:clojure/tools.build.git</connection>
<developerConnection>scm:git:git@github.com:clojure/tools.build.git</developerConnection>
<url>git@github.com:clojure/tools.build.git</url>
<tag>HEAD</tag>
</scm>
</project>
================================================
FILE: src/main/clojure/clojure/tools/build/api/specs.clj
================================================
(ns clojure.tools.build.api.specs
(:require [clojure.spec.alpha :as s]))
(s/def ::lib qualified-ident?)
(s/def ::path string?)
(s/def ::paths (s/coll-of string?))
;; there are better specs in clojure.tools.deps.specs, but no basis spec yet
;; just doing a simple check here
(s/def ::basis (s/nilable map?))
================================================
FILE: src/main/clojure/clojure/tools/build/api.clj
================================================
(ns clojure.tools.build.api
(:require
[clojure.java.io :as jio]
[clojure.set :as set]
[clojure.spec.alpha :as s]
[clojure.string :as str]
[clojure.tools.build.util.file :as file]
[clojure.tools.build.api.specs :as specs])
(:import
[java.io File]))
(set! *warn-on-reflection* true)
;; Project root dir, defaults to current directory
(def ^:dynamic *project-root*
"Project root path, defaults to current directory.
Use `resolve-path` to resolve relative paths in terms of the *project-root*.
Use `set-project-root!` to override the default for all tasks."
".")
(defn set-project-root!
"Set *project-root* dir (default is \".\")"
[root]
(alter-var-root #'*project-root* (constantly root)))
(defmacro with-project-root
"Execute forms in a bound project path (string) other than the default (\".\")"
[path & forms]
`(binding [*project-root* ~path] ~@forms))
(defn resolve-path
"If path is absolute or root-path is nil then return path,
otherwise resolve relative to *project-root*."
^File [path]
(let [path-file (jio/file path)]
(if (.isAbsolute path-file)
;; absolute, ignore root
path-file
;; relative to *project-root*
(jio/file *project-root* path-file))))
(defn- assert-required
"Check that each key in required coll is a key in params and throw if
required are missing in params, otherwise return nil."
[task params required]
(let [missing (set/difference (set required) (set (keys params)))]
(when (seq missing)
(throw (ex-info (format "Missing required params for %s: %s" task (vec (sort missing))) (or params {}))))))
(defn- assert-specs
"Check that key in params satisfies the spec. Throw if it exists and
does not conform to the spec, otherwise return nil."
[task params & key-specs]
(doseq [[key spec] (partition-all 2 key-specs)]
(let [val (get params key)]
(when (and val (not (s/valid? spec val)))
(throw (ex-info (format "Invalid param %s in call to %s: got %s, expected %s" key task (pr-str val) (s/form spec)) {}))))))
;; File tasks
(defn delete
"Delete file or directory recursively, if it exists. Returns nil.
Options:
:path - required, path to file or directory"
[{:keys [path] :as params}]
(assert-required "delete" params [:path])
(assert-specs "delete" params :path ::specs/path)
(let [root-file (resolve-path path)]
;(println "root-file" root-file)
(when (.exists root-file)
(file/delete root-file))))
(defn copy-file
"Copy one file from source to target, creating target dirs if needed.
Returns nil.
Options:
:src - required, source path
:target - required, target path"
[{:keys [src target] :as params}]
(assert-required "copy-file" params [:src :target])
(assert-specs "copy-file" params
:src ::specs/path
:target ::specs/path)
(file/copy-file (resolve-path src) (resolve-path target)))
(defn write-file
"Writes a file at path, will create parent dirs if needed. Returns nil.
File contents may be specified either with :content (for data, that
will be pr-str'ed) or with :string for the string to write. If
neither is specified, an empty file is created (like touch).
Options:
:path - required, file path
:content - val to write, will pr-str
:string - string to write
:opts - coll of writer opts like :append and :encoding (per clojure.java.io)"
[{:keys [path content string opts] :as params}]
(assert-required "write-file" params [:path])
(assert-specs "write-file" params :path ::specs/path)
(let [f (resolve-path path)]
(cond
content (apply file/ensure-file f (pr-str content) opts)
string (apply file/ensure-file f string opts)
:else (file/ensure-file f))))
(defn copy-dir
"Copy the contents of the src-dirs to the target-dir, optionally do text replacement.
Returns nil.
Globs are wildcard patterns for specifying sets of files in a directory
tree, as specified in the glob syntax of java.nio.file.FileSystem:
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/FileSystem.html#getPathMatcher(java.lang.String)
Options:
:target-dir - required, dir to write files, will be created if it doesn't exist
:src-dirs - required, coll of dirs to copy from
:include - glob of files to include, default = \"**\"
:ignores - collection of ignore regex patterns (applied only to file names),
see clojure.tools.build.tasks.copy/default-ignores for defaults
:replace - map of source to replacement string in files
:non-replaced-exts - coll of extensions to skip when replacing (still copied)
default = [\"jpg\" \"jpeg\" \"png\" \"gif\" \"bmp\"]"
[params]
(assert-required "copy" params [:target-dir :src-dirs])
(assert-specs "copy" params
:target-dir ::specs/path
:src-dirs ::specs/paths)
((requiring-resolve 'clojure.tools.build.tasks.copy/copy) params))
;; Basis tasks
(defn create-basis
"Create a basis from a set of deps sources and a set of aliases. By default, use
root, user, and project deps and no aliases (essentially the same classpath you
get by default from the Clojure CLI).
Each dep source value can be :standard, a string path, a deps edn map, or nil.
Sources are merged in the order - :root, :user, :project, :extra.
Options (note, paths resolved via *project-root*):
:dir - directory root path, defaults to current directory
:root - dep source, default = :standard
:user - dep source, default = nil (for reproducibility, not included)
:project - dep source, default = :standard (\"./deps.edn\")
:extra - dep source, default = nil
:aliases - coll of aliases of argmaps to apply to subprocesses
Returns a runtime basis, which is the initial merged deps edn map plus these keys:
:resolve-args - the resolve args passed in, if any
:classpath-args - the classpath args passed in, if any
:libs - lib map, per resolve-deps
:classpath - classpath map per make-classpath-map
:classpath-roots - vector of paths in classpath order"
([]
((requiring-resolve 'clojure.tools.build.tasks.create-basis/create-basis)))
([params]
((requiring-resolve 'clojure.tools.build.tasks.create-basis/create-basis) params)))
;; Process tasks
(defn java-command
"Create Java command line args. The classpath will be the combination of
:cp followed by the classpath from the basis, both are optional.
Note that 'java-command' will NOT resolve any relative paths from basis
or cp in terms of *project-root*, you will get a classpath with the same
relative paths. 'process' (if run with this output), will run in the
context of the *project-root* directory.
Options:
:java-cmd - Java command, default = $JAVA_CMD or 'java' on $PATH, or $JAVA_HOME/bin/java
:cp - coll of string classpath entries, used first (if provided)
:basis - runtime basis used for classpath and jvm opts from aliases, used last (if provided)
:java-opts - coll of string jvm opts
:main - required, main class symbol
:main-args - coll of main class args
:use-cp-file - one of:
:auto (default) - use only if os=windows && Java >= 9 && command length >= 8k
:always - always write classpath to temp file and include
:never - never write classpath to temp file (pass on command line)
Returns map suitable for passing to 'process' with keys:
:command-args - coll of command arg strings"
[params]
(assert-required "java-command" params [:main])
((requiring-resolve 'clojure.tools.build.tasks.process/java-command) params))
(defn process
"Exec the command made from command-args, redirect out and err as directed,
and return {:exit exit-code, :out captured-out, :err captured-err}.
Options:
:command-args - required, coll of string args
:dir - directory to run the command from, default *project-root*
:out - one of :inherit :capture :write :append :ignore
:err - one of :inherit :capture :write :append :ignore
:out-file - file path to write if :out is :write or :append
:err-file - file path to write if :err is :write or :append
:env - map of environment variables to set
The :out and :err input flags take one of the following options:
:inherit - inherit the stream and write the subprocess io to this process's stream (default)
:capture - capture the stream to a string and return it
:write - write to :out-file or :err-file
:append - append to :out-file or :err-file
:ignore - ignore the stream"
[params]
(assert-required "process" params [:command-args])
(assert-specs "process" params
:dir ::specs/path
:out-file ::specs/path
:err-file ::specs/path)
((requiring-resolve 'clojure.tools.build.tasks.process/process) params))
;; Git tasks
(defn git-process
"Run git process in the specified dir using git-command with git-args (which should not
start with \"git\"). git-args may either be a string (split on whitespace) or a vector
of strings. By default, stdout is captured, trimmed, and returned.
Options:
:dir - dir to invoke this command from, default = current directory
:git-command - git command to use, default = \"git\"
:git-args - required, coll of git-arg strings forming a command line OR
a string (do not use if args may have embedded spaces)
:capture - :out (default) or :err, else nothing
Examples:
(api/git-process {:git-args \"rev-list HEAD --count\"})
(api/git-process {:git-args \"branch --show-current\"})
(api/git-process {:git-args \"rev-parse --short HEAD\"})
(api/git-process {:git-args \"push\", :capture nil})"
[params]
(assert-required "git-command" params [:git-args])
(assert-specs "git-process" params
:dir ::specs/path
:git-command (s/nilable string?)
:git-args (s/or :args (s/coll-of string?) :line string?)
:capture (s/nilable keyword?))
(let [{:keys [dir git-command git-args capture] :or {git-command "git", capture :out}} params
git-args (vec
(concat [git-command]
(if (string? git-args)
(str/split git-args #"\s")
git-args)))
proc-params (cond-> {:command-args git-args}
capture (assoc capture :capture)
dir (assoc :dir (.getPath (resolve-path dir))))
output (process proc-params)]
(when capture
(some-> output capture str/trim))))
(defn git-count-revs
"Shells out to git and returns count of commits on this branch:
git rev-list HEAD --count
Options:
:dir - dir to invoke this command from, default = current directory
:git-command - git command to use, default = \"git\"
:path - path to count commits for relative to dir"
[{:keys [dir git-command path] :or {git-command "git"} :as params}]
(assert-specs "git-count-revs" params
:dir ::specs/path
:git-command (s/nilable string?)
:path ::specs/path)
(git-process
(cond-> {:git-args (cond-> ["rev-list" "HEAD" "--count"]
path (conj "--" path))}
dir (assoc :dir dir)
git-command (assoc :git-command git-command))))
;; Compile tasks
(defn compile-clj
"Compile Clojure source to classes in :class-dir.
Clojure source files are found in :basis :paths by default, or override with :src-dirs.
Namespaces and order of compilation are one of:
* :ns-compile - compile these namespaces, in this order
* :sort - find all namespaces in source files and use either :topo (default)
or :bfs to order them for compilation
Options:
:basis - required, basis to use when compiling
:class-dir - required, dir to write classes, will be created if needed
:src-dirs - coll of Clojure source dirs, used to find all Clojure nses to compile
:ns-compile - coll of specific namespace symbols to compile
:sort - :topo (default) or :bfs for breadth-first search
:compile-opts - map of Clojure compiler options:
{:disable-locals-clearing false
:elide-meta [:doc :file :line ...]
:direct-linking false}
:bindings - map of Var to value to be set during compilation, for example:
{#'clojure.core/*assert* false
#'clojure.core/*warn-on-reflection* true}
:filter-nses - coll of symbols representing a namespace prefix to include
Additional options flow to the forked process doing the compile:
:java-cmd - Java command, default = $JAVA_CMD or 'java' on $PATH, or $JAVA_HOME/bin/java
:java-opts - coll of string jvm opts
:use-cp-file - one of:
:auto (default) - use only if os=windows && Java >= 9 && command length >= 8k
:always - always write classpath to temp file and include
:never - never write classpath to temp file (pass on command line)
:out - one of :inherit :capture :write :append :ignore
:err - one of :inherit :capture :write :append :ignore
:out-file - file path to write if :out is :write or :append
:err-file - file path to write if :err is :write or :append
Returns nil, or if needed a map with keys:
:out captured-out
:err captured-err"
[params]
(assert-required "compile-clj" params [:basis :class-dir])
(assert-specs "compile-clj" params
:class-dir ::specs/path
:src-dirs ::specs/paths
:compile-opts map?
:bindings map?
:basis ::specs/basis)
((requiring-resolve 'clojure.tools.build.tasks.compile-clj/compile-clj) params))
(defn javac
"Compile Java source to classes. Returns nil.
Options:
:src-dirs - required, coll of Java source dirs
:class-dir - required, dir to write classes, will be created if needed
:basis - classpath basis to use when compiling
:javac-opts - coll of string opts, like [\"-source\" \"8\" \"-target\" \"8\"]"
[params]
(assert-required "javac" params [:src-dirs :class-dir])
(assert-specs "javac" params
:src-dirs ::specs/paths
:class-dir ::specs/path)
((requiring-resolve 'clojure.tools.build.tasks.javac/javac) params))
;; Jar/zip tasks
(defn pom-path
"Calculate path to pom.xml in jar meta (same path used by write-pom).
Relative path in jar is:
META-INF/maven/<groupId>/<artifactId>/pom.xml
If :class-dir provided, return path will start with resolved class-dir
(which may be either absolute or relative), otherwise just relative
path in jar.
Options:
:lib - required, used to form the relative path in jar to pom.xml
:class-dir - optional, if provided will be resolved and form the root of the path"
[params]
(assert-required "pom-path" params [:lib])
(assert-specs "pom-path" params
:lib ::specs/lib
:class-dir ::specs/path)
(let [{:keys [class-dir lib]} params
pom-dir ((requiring-resolve 'clojure.tools.build.tasks.write-pom/meta-maven-path) {:lib lib})
pom-file (if class-dir
(jio/file (resolve-path class-dir) pom-dir "pom.xml")
(jio/file pom-dir "pom.xml"))]
(.toString pom-file)))
(defn write-pom
"Write pom.xml and pom.properties files to the class dir under
META-INF/maven/group-id/artifact-id/ (where Maven typically writes
these files), or to target (exactly one of :class-dir and :target must
be provided).
Optionally use :src-pom to provide a pom template (or a default will
be generated from the provided attributes). The pom deps, dirs, and
repos from the basis will replace those sections of the template. Note
that the :src-pom template is not validated and should contain required
elements such as modelVersion.
If a repos map is provided it supersedes the repos in the basis.
Returns nil.
Options:
:basis - required, used to pull deps, repos
:src-pom - source pom.xml to synchronize from, default = \"./pom.xml\"
may be :none to ignore any existing pom.xml file
:class-dir - root dir for writing pom files, created if needed
:target - file path to write pom if no :class-dir specified
:lib - required, project lib symbol
:version - required, project version
:scm - map of scm properties to write in pom
keys: :connection, :developerConnection, :tag, :url
See: https://maven.apache.org/pom.html#SCM for details
:src-dirs - coll of src dirs
:resource-dirs - coll of resource dirs
:repos - map of repo name to repo config, replaces repos from deps.edn
:pom-data - vector of hiccup-style extra pom top elements to include when
:src-pom is :none or the source pom.xml does not exist:
[[:licenses
[:license
[:name \"Eclipse Public License 1.0\"]
[:url \"https://opensource.org/license/epl-1-0/\"]
[:distribution \"repo\"]]]
[:organization \"Super Corp\"]]
The pom-data MUST NOT include:
:modelVersion, :packaging, :groupId, :artifactId, :version, :name,
:deps, :repositories, :build, or :scm"
[params]
(assert-required "write-pom" params [:basis :lib :version])
(assert-specs "write-pom" params
:src-pom (s/or :none #{:none} :path ::specs/path)
:class-dir ::specs/path
:target ::specs/path
:lib ::specs/lib
:version string?
:scm map?
:src-dirs ::specs/paths
:resource-dirs ::specs/paths
:pom-data vector?)
((requiring-resolve 'clojure.tools.build.tasks.write-pom/write-pom) params))
(defn jar
"Create jar file containing contents of class-dir. Use main in the manifest
if provided. Returns nil.
Options:
:class-dir - required, dir to include in jar
:jar-file - required, jar to write
:main - main class symbol
:manifest - map of manifest attributes, merged last over defaults+:main"
[params]
(assert-required "jar" params [:class-dir :jar-file])
(assert-specs "jar" params
:class-dir ::specs/path
:jar-file ::specs/path)
((requiring-resolve 'clojure.tools.build.tasks.jar/jar) params))
(defn uber
"Create uberjar file. An uberjar is a self-contained jar file containing
both the project contents AND the contents of all dependencies.
The project contents are represented by the class-dir. Use other tasks to
put Clojure source, class files, a pom file, or other resources in the
class-dir. In particular, see the copy-dir, write-pom, compile-clj, and
javac tasks.
The dependencies are pulled from the basis. All transitive deps will be
included. Dependency jars are expanded for inclusion in the uberjar.
Use :exclude to exclude specific paths from the expanded deps. Use
conflict-handlers to handle conflicts that may occur if two dependency
jar files include a file at the same path. See below for more detail.
If a main class or manifest are provided, those are put in the uberjar
META-INF/MANIFEST.MF file. Providing a main allows the jar to be
invoked with java -jar.
Returns nil.
Options:
:uber-file - required, uber jar file to create
:class-dir - required, local class dir to include
:basis - used to pull dep jars
:main - main class symbol
:manifest - map of manifest attributes, merged last over defaults + :main
:exclude - coll of string patterns (regex) to exclude from deps
:conflict-handlers - map of string pattern (regex) to built-in handlers,
symbols to eval, or function instances
When combining jar files into an uber jar, multiple jars may contain a file
at the same path. The conflict handlers are a map of string regex pattern
to:
a keyword (to use a built-in handler) or
a symbol (to resolve and invoke) or
a function instance
The special key `:default` specifies the default behavior if not matched.
Conflict handler signature (fn [params]) => effect-map:
params:
:path - String, path in uber jar, matched by regex
:in - InputStream to incoming file (see stream->string if needed)
:existing - File, existing File at path
:lib - symbol, lib source for incoming conflict
:state - map, available for retaining state during uberjar process
Handler should return effect-map with optional keys:
:state - updated state map
:write - map of string path to map of :string (string) or
:stream (InputStream) to write and optional :append
flag. Omit if no files to write.
Available built-in conflict handlers:
:ignore - don't do anything (default)
:overwrite - overwrite (replaces prior file)
:append - append the file with a blank line separator
:append-dedupe - append the file but dedupe appended sections
:data-readers - merge data_readers.clj
:warn - print a warning
:error - throw an error
Default conflict handlers map:
{\"^data_readers.clj[c]?$\" :data-readers
\"^META-INF/services/.*\" :append
\"(?i)^(META-INF/)?(COPYRIGHT|NOTICE|LICENSE)(\\\\.(txt|md))?$\" :append-dedupe
:default :ignore}"
[params]
(assert-required "uber" params [:class-dir :uber-file])
(assert-specs "uber" params
:class-dir ::specs/path
:uber-file ::specs/path)
((requiring-resolve 'clojure.tools.build.tasks.uber/uber) params))
(defn zip
"Create zip file containing contents of src dirs. Returns nil.
Options:
:src-dirs - required, coll of source directories to include in zip
:zip-file - required, zip file to create"
[params]
(assert-required "zip" params [:src-dirs :zip-file])
(assert-specs "zip" params
:src-dirs ::specs/paths
:zip-file ::specs/path)
((requiring-resolve 'clojure.tools.build.tasks.zip/zip) params))
(defn unzip
"Unzip zip file to target-dir. Returns nil.
Options:
:zip-file - required, zip file to unzip
:target-dir - required, directory to unzip in"
[params]
(assert-required "unzip" params [:zip-file :target-dir])
(assert-specs "unzip" params
:zip-file ::specs/path
:target-dir ::specs/path)
((requiring-resolve 'clojure.tools.build.tasks.zip/unzip) params))
;; Maven tasks
(defn install
"Install pom and jar to local Maven repo.
Returns nil.
Options:
:basis - required, used for :mvn/local-repo
:lib - required, lib symbol
:classifier - classifier string, if needed
:version - required, string version
:jar-file - required, path to jar file
:class-dir - required, used to find the pom file"
[params]
(assert-required "install" params [:basis :lib :version :jar-file :class-dir])
(assert-specs "install" params
:lib ::specs/lib
:jar-file ::specs/path
:class-dir ::specs/path)
((requiring-resolve 'clojure.tools.build.tasks.install/install) params))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/compile_clj.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.compile-clj
(:require
[clojure.java.io :as jio]
[clojure.pprint :as pprint]
[clojure.string :as str]
[clojure.tools.build.api :as api]
[clojure.tools.build.util.file :as file]
[clojure.tools.build.tasks.process :as process]
[clojure.tools.namespace.find :as find]
[clojure.tools.namespace.dependency :as dependency]
[clojure.tools.namespace.parse :as parse])
(:import
[java.io File]
[java.nio.file Files]
[java.nio.file.attribute FileAttribute]))
(set! *warn-on-reflection* true)
(defn- write-compile-script!
^File [^File script-file ^File compile-dir nses compiler-opts bindings]
(let [compile-bindings (merge bindings
{#'*compile-path* (.toString compile-dir)
#'*compiler-options* compiler-opts})
binding-nses (->> compile-bindings
keys
(map #(-> % symbol namespace symbol)) ;; Var->namespace
distinct
(remove #(= % 'clojure.core)))
requires (map (fn [n] `(require '~n)) binding-nses)
do-compile `(with-bindings ~compile-bindings
~@(map (fn [n] `(~'compile '~n)) nses)
(System/exit 0))
script (->> (conj (vec requires) do-compile)
(map #(with-out-str (pprint/pprint %)))
(str/join (System/lineSeparator)))]
(spit script-file script)))
(defn- ns->path
[ns-sym]
(str/replace (clojure.lang.Compiler/munge (str ns-sym)) \. \/))
(defn- nses-in-bfs
[dirs]
(mapcat #(find/find-namespaces-in-dir % find/clj) dirs))
(defn- nses-in-topo
[dirs]
(let [ns-decls (mapcat find/find-ns-decls-in-dir dirs)
ns-candidates (set (map parse/name-from-ns-decl ns-decls))
graph (reduce
(fn [graph decl]
(let [sym (parse/name-from-ns-decl decl)]
(reduce
(fn [graph dep] (dependency/depend graph sym dep))
graph
(parse/deps-from-ns-decl decl))))
(dependency/graph)
ns-decls)]
(->> graph
dependency/topo-sort
(filter ns-candidates) ;; only keep stuff in these dirs
(#(concat % ns-candidates)) ;; but make sure everything is in there at least once
distinct)))
(defn- basis-paths
"Extract all path entries from basis, in classpath order"
[{:keys [classpath classpath-roots]}]
(let [path-set (->> classpath
(filter #(contains? (val %) :path-key))
(map key)
set)]
(filter path-set classpath-roots)))
(defn compile-clj
[{:keys [basis src-dirs compile-opts ns-compile filter-nses class-dir sort bindings] :as params
:or {sort :topo}}]
(let [working-dir (.toFile (Files/createTempDirectory "compile-clj" (into-array FileAttribute [])))
compile-dir-file (file/ensure-dir (api/resolve-path class-dir))
clj-paths (map api/resolve-path (or src-dirs (basis-paths basis)))
nses (cond
(seq ns-compile) ns-compile
(= sort :topo) (nses-in-topo clj-paths)
(= sort :bfs) (nses-in-bfs clj-paths)
:else (throw (ex-info "Missing :ns-compile or :sort order in compile-clj task" {})))
working-compile-dir (file/ensure-dir (jio/file working-dir "compile-clj"))
compile-script (jio/file working-dir "compile.clj")
_ (write-compile-script! compile-script working-compile-dir nses compile-opts bindings)
;; java-command will run in context of *project-dir* - basis, classpaths, etc
;; should all be relative to that (or absolute like working-compile-dir)
process-args (merge
(process/java-command
(merge
(select-keys params [:java-cmd :java-opts :use-cp-file])
{:cp [(.getPath working-compile-dir) class-dir]
:basis basis
:main 'clojure.main
:main-args [(.getCanonicalPath compile-script)]}))
(select-keys params [:out :err :out-file :err-file]))
_ (spit (jio/file working-dir "compile.args") (str/join " " (:command-args process-args)))
{exit :exit, ps-out :out, ps-err :err} (process/process process-args)
ret (cond-> nil
ps-out (assoc :out ps-out)
ps-err (assoc :err ps-err))]
(if (zero? exit)
(do
(if (seq filter-nses)
(file/copy-contents working-compile-dir compile-dir-file (map ns->path filter-nses))
(file/copy-contents working-compile-dir compile-dir-file))
;; only delete on success, otherwise leave the evidence!
(file/delete working-dir)
ret)
(throw (ex-info (str "Clojure compilation failed, working dir preserved: " (.toString working-dir)) ret)))))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/copy.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.copy
(:require
[clojure.string :as str]
[clojure.tools.build.api :as api]
[clojure.tools.build.util.file :as file])
(:import
[java.io File]
[java.nio.file FileSystems FileVisitor FileVisitResult Files Path LinkOption]))
(set! *warn-on-reflection* true)
;; copy spec:
;; :from (coll of dirs), default = ["."]
;; ;include (glob), default = "**"
;; :replace (map of replacements) - performed while copying
(defn- match-paths
"Match glob to paths under root and return a collection of Path objects"
[^File root glob]
(let [root-path (.toPath root)
matcher (.getPathMatcher (FileSystems/getDefault) (str "glob:" glob))
paths (volatile! [])
visitor (reify FileVisitor
(visitFile [_ path _attrs]
(when (.matches matcher (.relativize root-path ^Path path))
(vswap! paths conj path))
FileVisitResult/CONTINUE)
(visitFileFailed [_ _path _ex] FileVisitResult/CONTINUE)
(preVisitDirectory [_ _ _] FileVisitResult/CONTINUE)
(postVisitDirectory [_ _ _] FileVisitResult/CONTINUE))]
(Files/walkFileTree root-path visitor)
@paths))
(def default-ignores
[".*~$"
"^#.*#$"
"^\\.#.*"
"^.DS_Store$"])
(defn ignore? [name ignore-regexes]
(boolean (some #(re-matches % name) ignore-regexes)))
(def default-non-replaced-exts
["jpg" "jpeg" "png" "gif" "bmp"])
(defn- ends-with-ext?
[exts path]
(loop [[ext & es] exts]
(if ext
(if (str/ends-with? path ext)
true
(recur es))
false)))
(defn copy
[{:keys [target-dir src-dirs include replace ignores non-replaced-exts]
:or {include "**", ignores default-ignores, non-replaced-exts default-non-replaced-exts}
:as _params}]
(let [to-path (.toPath (file/ensure-dir (api/resolve-path target-dir)))
ignore-regexes (map re-pattern ignores)
non-replaced (map #(str "." %) default-non-replaced-exts)]
(doseq [dir src-dirs]
;(println "from" dir)
(let [from-file (api/resolve-path dir)
paths (match-paths from-file include)]
(doseq [^Path path paths]
(let [path-file (.toFile path)
path-file-name (.getName path-file)
target-file (.toFile (.resolve to-path (.relativize (.toPath from-file) path)))]
(when-not (ignore? path-file-name ignore-regexes)
;(println "copying" (.toString path-file) (.toString target-file) (boolean (not (empty? replace))))
(if (or (empty? replace) (ends-with-ext? non-replaced (.getName path-file)))
(file/copy-file path-file target-file)
(let [contents (slurp path-file)
replaced (reduce (fn [s [find replace]] (str/replace s find replace))
contents replace)
perms (when (contains? (.supportedFileAttributeViews (FileSystems/getDefault)) "posix")
(Files/getPosixFilePermissions (.toPath path-file)
(into-array LinkOption [LinkOption/NOFOLLOW_LINKS])))]
(file/ensure-file target-file replaced :append false)
(when perms
(Files/setPosixFilePermissions (.toPath target-file) perms)
nil))))))))))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/create_basis.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.create-basis
(:require
[clojure.java.io :as jio]
[clojure.tools.build.api :as api]
[clojure.tools.deps :as deps]
[clojure.tools.deps.util.dir :as dir]))
(defn create-basis
"Wrapper for deps/create-basis, but ensure relative paths are resolved
relative to *project-root*.
Options (note, paths resolved via *project-root*):
:root - dep source, default = :standard
:user - dep source, default = nil
:project - dep source, default = :standard (\"./deps.edn\")
:extra - dep source, default = nil
:aliases - coll of aliases of argmaps to apply to subprocesses"
([]
(create-basis nil))
([params]
(dir/with-dir (jio/file api/*project-root*)
(deps/create-basis (merge {:user nil} params)))))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/install.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.install
(:require
[clojure.java.io :as jio]
[clojure.tools.deps.util.maven :as mvn]
[clojure.tools.build.api :as api])
(:import
[org.eclipse.aether.artifact DefaultArtifact]
[org.eclipse.aether.installation InstallRequest]))
(set! *warn-on-reflection* true)
(defn install
[{:keys [basis lib classifier version jar-file class-dir] :as params}]
(let [{:mvn/keys [local-repo]} basis
group-id (namespace lib)
artifact-id (name lib)
jar-file-file (api/resolve-path jar-file)
pom-dir (jio/file (api/resolve-path class-dir) "META-INF" "maven" group-id artifact-id)
pom (jio/file pom-dir "pom.xml")
system (mvn/make-system)
session (mvn/make-session system (or local-repo @mvn/cached-local-repo))
jar-artifact (.setFile (DefaultArtifact. group-id artifact-id classifier "jar" version) jar-file-file)
artifacts (cond-> [jar-artifact]
(and pom-dir (.exists pom)) (conj (.setFile (DefaultArtifact. group-id artifact-id classifier "pom" version) pom)))
install-request (.setArtifacts (InstallRequest.) artifacts)]
(.install system session install-request)
nil))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/jar.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.jar
(:require
[clojure.java.io :as jio]
[clojure.tools.build.api :as api]
[clojure.tools.build.util.file :as file]
[clojure.tools.build.util.zip :as zip]
[clojure.string :as str])
(:import
[java.util.jar Manifest JarOutputStream]))
(defn jar
[{mf-attrs :manifest, :keys [class-dir jar-file main] :as params}]
(let [jar-file (api/resolve-path jar-file)
class-dir-file (file/ensure-dir (api/resolve-path class-dir))
mf-attr-strs (reduce-kv (fn [m k v] (assoc m (str k) (str v))) nil mf-attrs)]
(file/ensure-dir (.getParent jar-file))
(let [manifest (Manifest.)]
(zip/fill-manifest! manifest
(merge
(cond->
{"Manifest-Version" "1.0"
"Created-By" "org.clojure/tools.build"
"Build-Jdk-Spec" (System/getProperty "java.specification.version")}
main (assoc "Main-Class" (str/replace (str main) \- \_)))
mf-attr-strs))
(with-open [jos (JarOutputStream. (jio/output-stream jar-file) manifest)]
(zip/copy-to-zip jos class-dir-file)))))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/javac.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.javac
(:require
[clojure.string :as str]
[clojure.tools.build.api :as api]
[clojure.tools.build.util.file :as file])
(:import
[java.io File]
[javax.tools ToolProvider DiagnosticListener]))
(set! *warn-on-reflection* true)
(defn javac
[{:keys [basis javac-opts class-dir src-dirs] :as params}]
(let [{:keys [libs]} basis]
(when (seq src-dirs)
(let [class-dir (file/ensure-dir (api/resolve-path class-dir))
compiler (ToolProvider/getSystemJavaCompiler)
listener (reify DiagnosticListener (report [_ diag] (println (str diag))))
file-mgr (.getStandardFileManager compiler listener nil nil)
class-dir-path (.getPath class-dir)
classpath (str/join File/pathSeparator (conj (mapcat :paths (vals libs)) class-dir-path))
options (concat ["-classpath" classpath "-d" class-dir-path] javac-opts)
java-files (mapcat #(file/collect-files (api/resolve-path %) :collect (file/suffixes ".java")) src-dirs)
file-objs (.getJavaFileObjectsFromFiles file-mgr java-files)
task (.getTask compiler nil file-mgr listener options nil file-objs)
success (.call task)]
(when-not success
(throw (ex-info "Java compilation failed" {})))))))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/process.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.process
(:require
[clojure.java.io :as jio]
[clojure.java.process :as proc]
[clojure.tools.deps :as deps]
[clojure.tools.build.api :as api]
[clojure.string :as str])
(:import
[java.io File]))
(set! *warn-on-reflection* true)
(defn- trim-blank [^String s]
(if (str/blank? s) nil s))
(defn process
"Exec the command made from command-args, redirect out and err as directed,
and return {:exit exit-code, :out captured-out, :err captured-err}
Options:
:command-args - required, coll of string args
:dir - directory to run the command from, default current directory
:out - one of :inherit :capture :write :append :ignore
:err - one of :inherit :capture :write :append :ignore
:out-file - file path to write if :out is :write or :append
:err-file - file path to write if :err is :write or :append
:env - map of environment variables to set
The :out and :err input flags take one of the following options:
:inherit - inherit the stream and write the subprocess io to this process's stream (default)
:capture - capture the stream to a string and return it
:write - write to :out-file or :err-file
:append - append to :out-file or :err-file
:ignore - ignore the stream"
[{:keys [command-args dir env out err out-file err-file]
:or {dir ".", out :inherit, err :inherit} :as opts}]
(when (not (seq command-args))
(throw (ex-info "process missing required arg :command-args" opts)))
(let [stream-opt (fn [opt file]
(case opt
:inherit :inherit
:write (proc/to-file (api/resolve-path file))
:append (proc/to-file (api/resolve-path file) :append true)
:ignore :discard
(:capture :pipe) :pipe))
proc-opts {:dir (api/resolve-path (or dir "."))
:out (stream-opt out out-file)
:err (stream-opt err err-file)
:env env}
proc (apply proc/start proc-opts command-args)
out-f (when (= out :capture) (proc/io-task #(slurp (proc/stdout proc))))
err-f (when (= err :capture) (proc/io-task #(slurp (proc/stderr proc))))
exit (deref (proc/exit-ref proc))
out-str (when out-f (trim-blank @out-f))
err-str (when err-f (trim-blank @err-f))]
(cond-> {:exit exit}
out-str (assoc :out out-str)
err-str (assoc :err err-str))))
(comment
(api/process {:command-args ["ls" "-l"]})
(api/process {:command-args ["git" "log"] :out :ignore})
(api/process {:command-args ["java" "-version"] :err :capture})
(api/process {:command-args ["java" "--version"] :out :capture})
(api/process {:env {"FOO" "hi"}
:command-args ["echo" "$FOO"]
:out :capture})
)
(defn- need-cp-file
[os-name java-version command-length]
(and
;; this is only an issue on Windows
(str/starts-with? os-name "Win")
;; CLI support only exists in Java 9+, for Java <= 1.8, the version number is 1.x
(not (str/starts-with? java-version "1."))
;; the actual limit on windows is 8191 (<8k), but giving some room
(> command-length 8000)))
(defn- make-java-args
[java-cmd java-opts cp main main-args use-cp-file]
(let [full-args (vec (concat [java-cmd] java-opts ["-cp" cp (name main)] main-args))
arg-str (str/join " " full-args)]
(if (or (= use-cp-file :always)
(and (= use-cp-file :auto)
(need-cp-file (System/getProperty "os.name") (System/getProperty "java.version") (count arg-str))))
(let [cp-file (doto (File/createTempFile "tbuild-" ".cp") (.deleteOnExit))]
(spit cp-file cp)
(vec (concat [java-cmd] java-opts ["-cp" (str "@" (.getAbsolutePath cp-file)) (name main)] main-args)))
full-args)))
(defn which
"Given the name of an executable, return either a full path to
its location on the system PATH or nil if not found"
[cmd]
(when-let [path (System/getenv "PATH")]
(let [paths (str/split path (re-pattern File/pathSeparator))]
(loop [paths paths]
(when-first [p paths]
(let [f (jio/file p cmd)]
(if (and (.isFile f) (.canExecute f))
(.getCanonicalPath f)
(recur (rest paths)))))))))
(defn- windows?
[]
(str/starts-with? (System/getProperty "os.name") "Windows"))
(defn- java-exe
[]
(if (windows?) "java.exe" "java"))
(defn- java-home-bin
"Returns path $JAVA_HOME/bin/java if JAVA_HOME set, or nil"
[]
(when-let [jhome (System/getenv "JAVA_HOME")]
(let [exe (jio/file jhome "bin" (java-exe))]
(when (and (.exists exe) (.canExecute exe))
(.getCanonicalPath exe)))))
(defn java-executable
"Given the environment, emulate the Clojure CLI logic to determine the
Java executable path and return it by trying in order:
$JAVA_CMD
java on the PATH
$JAVA_HOME/bin/java"
[]
(or
(System/getenv "JAVA_CMD")
(which (java-exe))
(java-home-bin)
(throw (ex-info "Couldn't find java executable via $JAVA_CMD, $PATH, or $JAVA_HOME" {}))))
(defn java-command
"Create Java command line args. The classpath will be the combination of
:cp followed by the classpath from the basis, both are optional.
Options:
:java-cmd - Java command, default = $JAVA_CMD or 'java' on $PATH, or $JAVA_HOME/bin/java
:cp - coll of string classpath entries, used first (if provided)
:basis - runtime basis used for classpath, used last (if provided)
:java-opts - coll of string jvm opts
:main - required, main class symbol
:main-args - coll of main class args
:use-cp-file - one of:
:auto (default) - use only if os=windows && Java >= 9 && command length >= 8k
:always - always write classpath to temp file and include
:never - never write classpath to temp file (pass on command line)
Returns:
:command-args - coll of command arg strings"
[{:keys [java-cmd cp basis java-opts main main-args use-cp-file]
:or {use-cp-file :auto} :as _params}]
(let [cmd (or java-cmd (java-executable))
{:keys [classpath-roots argmap]} basis
cp-entries (concat cp classpath-roots)
cp-str (deps/join-classpath cp-entries)
combined-java-opts (concat java-opts (:jvm-opts argmap))]
{:command-args (make-java-args cmd combined-java-opts cp-str main main-args use-cp-file)}))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/uber.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.uber
(:require
[clojure.java.io :as jio]
[clojure.pprint :as pprint]
[clojure.set :as set]
[clojure.string :as str]
[clojure.tools.build.api :as api]
[clojure.tools.build.util.file :as file]
[clojure.tools.build.util.zip :as zip])
(:import
[java.io File InputStream IOException OutputStream ByteArrayOutputStream]
[java.nio.file Files]
[java.nio.file.attribute FileAttribute FileTime]
[java.util.jar JarEntry JarInputStream JarOutputStream Manifest]))
(set! *warn-on-reflection* true)
(def ^:private uber-exclusions
[#"project.clj"
#"META-INF/.*\.(?:SF|RSA|DSA|MF)"
#"module-info\.class"
#"(.*/)?\.DS_Store" ;; Mac metadata
#".+~" ;; emacs backup files
#".#.*" ;; emacs
#"(.*/)?\.keep" ;; convention in dirs to keep that are empty
#".*\.pom"
#"(?i)META-INF/(?:INDEX\.LIST|DEPENDENCIES)(?:\.txt)?"])
(defn- exclude-from-uber?
[exclude-patterns ^String path]
(loop [[re & res] exclude-patterns]
(if re
(if (re-matches re path)
true
(recur res))
false)))
(defn- copy-stream!
"Copy input stream to output stream using buffer.
Caller is responsible for passing buffered streams and closing streams."
[^InputStream is ^OutputStream os ^bytes buffer]
(loop []
(let [size (.read is buffer)]
(if (pos? size)
(do
(.write os buffer 0 size)
(recur))
(.close os)))))
(defn- stream->string
[^InputStream is]
(let [baos (ByteArrayOutputStream. 4096)
_ (copy-stream! is baos (byte-array 4096))]
(.toString baos "UTF-8")))
(defn conflict-overwrite
[{:keys [path in]}]
{:write {path {:stream in}}})
(defn- conflict-append
[{:keys [path in]}]
{:write {path {:string (str "\n" (stream->string in)), :append true}}})
(defn- conflict-append-dedupe
[{:keys [path in ^File existing state] :as _params}]
(let [existing-content (slurp existing)
existing-lower (str/lower-case existing-content)
new-content (stream->string in)
new-content-lower (str/lower-case new-content)
seen (or (get-in state [:append-dedupe path]) #{existing-lower})]
(if (contains? seen new-content-lower)
;; already seen
{:state (assoc-in state [:append-dedupe path] seen)}
;; record and append
{:state (assoc-in state [:append-dedupe path] (conj seen new-content))
:write {path {:string (str "\n" new-content), :append true}}})))
(defn conflict-data-readers
[{:keys [path in ^File existing]}]
(binding [*read-eval* false]
(let [existing-str (slurp existing)
existing-reader-fns (read-string
{:read-cond :preserve :features #{:clj}}
existing-str)
append-reader-fns (read-string
{:read-cond :preserve :features #{:clj}}
(stream->string in))
reader-str (with-out-str (pprint/pprint (merge existing-reader-fns append-reader-fns)))]
{:write {path {:string reader-str}}})))
(defn- conflict-warn
[{:keys [path lib]}]
(println "Conflicting path at" path "from" lib))
(defn- conflict-error
[{:keys [path lib]}]
(throw (ex-info (str "Conflicting path at " path " from " lib) {})))
(defn- handler-emit
[^FileTime last-modified-time buffer out-dir path write-spec]
(let [{:keys [string stream append] :or {append false}} write-spec
out-file (jio/file out-dir path)]
(if string
(spit out-file string :append ^boolean append)
(copy-stream! ^InputStream stream (jio/output-stream out-file :append append) buffer))
(Files/setLastModifiedTime (.toPath out-file) last-modified-time)))
(defn- handle-conflict
[handlers last-modified-time buffer out-dir {:keys [state path] :as handler-params}]
(let [use-handler (loop [[[re handler] & hs] (dissoc handlers :default)]
(if re
(if (re-matches re path)
handler
(recur hs))
(:default handlers)))]
(if use-handler
(let [{new-state :state, write :write} (use-handler handler-params)]
(when write
(doseq [[path write-spec] write]
(handler-emit last-modified-time buffer out-dir path write-spec)))
(or new-state state))
(throw (ex-info (format "No handler found for conflict at %s" path) {})))))
(defn- ensure-dir
"Returns true if parent dir exists, false if exists but is not a file,
and throws if it cannot be created."
[^File parent ^File child]
(if (.exists parent)
(.isDirectory parent)
(if (jio/make-parents child)
true
(throw (ex-info (str "Unable to create parent dirs for: " (.toString child)) {})))))
(defn- explode1
"Given one entry/src file, copy to target pursuant to excludes and handlers.
Returns possibly updated state for further exploding."
[^InputStream is ^String path dir? ^FileTime last-modified-time
^File out-file lib {:keys [out-dir buffer exclude handlers] :as context} state]
(cond
;; excluded or directory - do nothing
(or (exclude-from-uber? exclude path) dir?)
state
;; conflict, same file from multiple sources - handle
(.exists out-file)
(handle-conflict handlers last-modified-time buffer out-dir
{:lib lib, :path path, :in is, :existing out-file, :state state})
;; write new file, parent dir exists for writing
(ensure-dir (.getParentFile out-file) out-file)
(do
(copy-stream! ^InputStream is (jio/output-stream out-file) buffer)
(Files/setLastModifiedTime (.toPath out-file) last-modified-time)
state)
:parent-dir-is-a-file
(throw (ex-info (format "Cannot write %s from %s as parent dir is a file from another lib. One of them must be excluded."
path lib) {}))))
(defn- explode
[^File lib-file lib {:keys [out-dir buffer exclude handlers] :as context} state]
(cond
(not (.exists lib-file))
state
(str/ends-with? (.getPath lib-file) ".jar")
(with-open [jis (JarInputStream. (jio/input-stream lib-file))]
(loop [the-state state]
(if-let [entry (.getNextJarEntry jis)]
(let [path (.getName entry)
;; should rarely happen (except /), but chop to make relative:
path (if (str/starts-with? path "/") (subs path 1) path)
out-file (jio/file out-dir path)]
(recur
(explode1 jis path (.isDirectory entry) (.getLastModifiedTime ^JarEntry entry)
out-file lib context the-state)))
the-state)))
(.isDirectory lib-file)
(let [source-dir (.getAbsoluteFile lib-file)
source-path (.toPath source-dir)
fs (file/collect-files source-dir :dirs true)]
(loop [[^File f & restf] fs, the-state state]
(if f
(let [is (when (.isFile f)
(try
(jio/input-stream f)
(catch IOException e
(throw (ex-info (str "Uber task found file but can't read its content in " lib " at path " (.getPath f))
{:path (.getPath f)} e)))))
new-state (try
(let [path (str/replace (.toString (.relativize source-path (.toPath f))) \\ \/)
source-time (FileTime/fromMillis (.lastModified f))
out-file (jio/file out-dir path)]
(explode1 is path (.isDirectory f) source-time out-file lib context the-state))
(finally
(when is (.close ^InputStream is))))]
(recur restf new-state))
the-state)))
:else
(throw (ex-info (format "Unexpected lib file: %s" (.toString lib-file)) {}))))
(defn- remove-optional
"Remove optional libs and their transitive dependencies from the lib tree.
Only remove transitive if all dependents are optional."
[libs]
(let [by-opt (group-by (fn [[_lib coord]] (boolean (:optional coord))) libs)
optional (apply conj {} (get by-opt true))]
(if (seq optional)
(loop [req (get by-opt false)
opt optional]
(let [under-opts (group-by (fn [[_lib {:keys [dependents]}]]
(boolean
(and (seq dependents)
(set/subset? (set dependents) (set (keys opt))))))
req)
trans-opt (get under-opts true)]
(if (seq trans-opt)
(recur (get under-opts false) (into opt trans-opt))
(apply conj {} req))))
libs)))
(defn- built-ins
[kw]
(or
(get {:ignore (fn [_])
:overwrite conflict-overwrite
:append conflict-append
:append-dedupe conflict-append-dedupe
:data-readers conflict-data-readers
:warn conflict-warn
:error conflict-error}
kw)
(throw (ex-info (str "Invalid handler: " kw) {}))))
(defn- prep-handler
"Convert user handler to fn"
[handler]
(cond
(keyword? handler) (built-ins handler)
(symbol? handler) (deref (requiring-resolve handler))
(ifn? handler) handler
:else (throw (ex-info (str "Invalid handler: " handler) {}))))
(def ^:private default-handlers
{"^data_readers.clj[c]?$" :data-readers
"^META-INF/services/.*" :append
"(?i)^(META-INF/)?(COPYRIGHT|NOTICE|LICENSE)(\\.(txt|md))?$" :append-dedupe
:default :ignore})
(defn- prep-handlers
"Transform user handler map into a map of re->fn"
[handlers]
(reduce-kv
(fn [m pattern handler]
(assoc m (if (= pattern :default) :default (re-pattern pattern))
(prep-handler handler)))
{} (merge default-handlers handlers)))
(defn uber
[{mf-attrs :manifest, :keys [basis class-dir uber-file main exclude conflict-handlers]}]
(let [working-dir (.toFile (Files/createTempDirectory "uber" (into-array FileAttribute [])))
context {:out-dir working-dir
:buffer (byte-array 4096)
:handlers (prep-handlers conflict-handlers)
:exclude (map re-pattern (into uber-exclusions exclude))}]
(try
(let [{:keys [libs]} basis
compile-dir (api/resolve-path class-dir)
manifest (Manifest.)
uber-file (api/resolve-path uber-file)
mf-attr-strs (reduce-kv (fn [m k v] (assoc m (str k) (str v))) nil mf-attrs)]
(reduce
(fn [state [lib coord]]
(reduce
(fn [state path] (explode (jio/file path) lib context state))
state (:paths coord)))
nil ;; initial state, usable by handlers if needed
(assoc (remove-optional libs) nil {:paths [compile-dir]}))
(zip/fill-manifest! manifest
(merge
(cond->
{"Manifest-Version" "1.0"
"Created-By" "org.clojure/tools.build"
"Build-Jdk-Spec" (System/getProperty "java.specification.version")}
main (assoc "Main-Class" (str/replace (str main) \- \_))
(.exists (jio/file working-dir "META-INF" "versions")) (assoc "Multi-Release" "true"))
mf-attr-strs))
(file/ensure-dir (.getParent uber-file))
(with-open [jos (JarOutputStream. (jio/output-stream uber-file) manifest)]
(zip/copy-to-zip jos working-dir)))
(finally
(file/delete working-dir)))))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/write_pom.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.write-pom
(:require
[clojure.java.io :as jio]
[clojure.string :as str]
[clojure.data.xml :as xml]
[clojure.data.xml.tree :as tree]
[clojure.data.xml.event :as event]
[clojure.walk :as walk]
[clojure.zip :as zip]
[clojure.tools.deps.util.maven :as maven]
[clojure.tools.deps.util.io :refer [printerrln]]
[clojure.tools.build.api :as api]
[clojure.tools.build.util.file :as file])
(:import [clojure.data.xml.node Element]
[java.io Reader]
[java.time Instant ZoneId ZonedDateTime]
[java.time.format DateTimeFormatter]))
(set! *warn-on-reflection* true)
(xml/alias-uri 'pom "http://maven.apache.org/POM/4.0.0")
(def ^:private pom-ns (name (.-name ^clojure.lang.Namespace (get (ns-aliases *ns*) 'pom))))
(defn- to-dep
[[lib {:keys [mvn/version exclusions optional] :as coord}]]
(let [[group-id artifact-id classifier] (maven/lib->names lib)]
(if version
(cond->
[::pom/dependency
[::pom/groupId group-id]
[::pom/artifactId artifact-id]
[::pom/version version]]
classifier
(conj [::pom/classifier classifier])
(seq exclusions)
(conj [::pom/exclusions
(map (fn [excl]
[::pom/exclusion
[::pom/groupId (or (namespace excl) (name excl))]
[::pom/artifactId (name excl)]])
exclusions)])
optional
(conj [::pom/optional "true"]))
(printerrln "Skipping coordinate:" coord))))
(defn- gen-deps
[deps]
[::pom/dependencies
(map to-dep deps)])
(defn- gen-source-dir
[path]
[::pom/sourceDirectory path])
(defn- to-resource
[resource]
[::pom/resource
[::pom/directory resource]])
(defn- gen-resources
[rpaths]
[::pom/resources
(map to-resource rpaths)])
(defn- to-repo-policy
[parent-tag {:keys [enabled update checksum]}]
[parent-tag
(when (some? enabled) [::pom/enabled (str enabled)])
(when update [::pom/updatePolicy (if (keyword? update) (name update) (str "interval:" update))])
(when checksum [::pom/checksumPolicy (name checksum)])])
(defn- to-repo
[[name {:keys [url snapshots releases]}]]
[::pom/repository
[::pom/id name]
[::pom/url url]
(when releases (to-repo-policy ::pom/releases releases))
(when snapshots (to-repo-policy ::pom/snapshots snapshots))])
(defn- gen-repos
[repos]
[::pom/repositories
(map to-repo repos)])
(defn- pomify
[val]
(if (and (vector? val) (keyword? (first val)))
(into [(keyword pom-ns (name (first val)))] (rest val))
val))
(defn- gen-pom
[{:keys [deps src-paths resource-paths repos group artifact version scm pom-data]
:or {version "0.1.0"}}]
(let [[path & paths] src-paths
{:keys [connection developerConnection tag url]} scm]
(xml/sexp-as-element
(into
[::pom/project
{:xmlns "http://maven.apache.org/POM/4.0.0"
(keyword "xmlns:xsi") "http://www.w3.org/2001/XMLSchema-instance"
(keyword "xsi:schemaLocation") "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"}
[::pom/modelVersion "4.0.0"]
[::pom/packaging "jar"]
[::pom/groupId group]
[::pom/artifactId artifact]
[::pom/version version]
[::pom/name artifact]
(gen-deps deps)
(when (or path (seq resource-paths))
(when (seq paths) (apply printerrln "Skipping paths:" paths))
[::pom/build
(when path (gen-source-dir path))
(when (seq resource-paths) (gen-resources resource-paths))])
(gen-repos repos)
(when scm
[::pom/scm
(when connection [::pom/connection connection])
(when developerConnection [::pom/developerConnection developerConnection])
(when tag [::pom/tag tag])
(when url [::pom/url url])])]
(walk/postwalk pomify pom-data)))))
(defn- make-xml-element
[{:keys [tag attrs] :as node} children]
(with-meta
(apply xml/element tag attrs children)
(meta node)))
(defn- xml-update
[root tag-path replace-node]
(let [z (zip/zipper xml/element? :content make-xml-element root)]
(zip/root
(loop [[tag & more-tags :as tags] tag-path, parent z, child (zip/down z)]
(if child
(if (= tag (:tag (zip/node child)))
(if (seq more-tags)
(recur more-tags child (zip/down child))
(zip/edit child (constantly replace-node)))
(if-let [next-sibling (zip/right child)]
(recur tags parent next-sibling)
(if (seq more-tags)
(let [new-parent (zip/append-child parent (xml/sexp-as-element tag))
new-child (zip/rightmost (zip/down new-parent))]
(recur more-tags new-child (zip/down new-child)))
(zip/append-child parent replace-node))))
(if (seq more-tags)
(let [new-parent (zip/append-child parent (xml/sexp-as-element tag))
new-child (zip/rightmost (zip/down new-parent))]
(recur more-tags new-child (zip/down new-child)))
(zip/append-child parent replace-node)))))))
(defn- replace-deps
[pom deps]
(xml-update pom [::pom/dependencies] (xml/sexp-as-element (gen-deps deps))))
(defn- replace-paths
[pom [path & paths]]
(if path
(do
(when (seq paths) (apply printerrln "Skipping paths:" paths))
(xml-update pom [::pom/build ::pom/sourceDirectory] (xml/sexp-as-element (gen-source-dir path))))
pom))
(defn- replace-resources
[pom resource-paths]
(if (seq resource-paths)
(xml-update pom [::pom/build ::pom/resources] (xml/sexp-as-element (gen-resources resource-paths)))
pom))
(defn- replace-repos
[pom repos]
(if (seq repos)
(xml-update pom [::pom/repositories] (xml/sexp-as-element (gen-repos repos)))
pom))
(defn- replace-lib
[pom lib]
(if lib
(-> pom
(xml-update [::pom/groupId] (xml/sexp-as-element [::pom/groupId (namespace lib)]))
(xml-update [::pom/artifactId] (xml/sexp-as-element [::pom/artifactId (name lib)]))
(xml-update [::pom/name] (xml/sexp-as-element [::pom/name (name lib)])))
pom))
(defn- replace-version
[pom version]
(if version
(xml-update pom [::pom/version] (xml/sexp-as-element [::pom/version version]))
pom))
(defn- replace-scm
[pom {:keys [connection developerConnection tag url] :as scm}]
(if scm
(cond-> pom
connection (xml-update [::pom/scm ::pom/connection] (xml/sexp-as-element [::pom/connection connection]))
developerConnection (xml-update [::pom/scm ::pom/developerConnection] (xml/sexp-as-element [::pom/developerConnection developerConnection]))
tag (xml-update [::pom/scm ::pom/tag] (xml/sexp-as-element [::pom/tag tag]))
url (xml-update [::pom/scm ::pom/url] (xml/sexp-as-element [::pom/url url])))
pom))
(defn- parse-xml
[^Reader rdr]
(let [roots (tree/seq-tree event/event-element event/event-exit? event/event-node
(xml/event-seq rdr {:include-node? #{:element :characters :comment}
:skip-whitespace true}))]
(first (filter #(instance? Element %) (first roots)))))
(defn- libs->deps
"Convert libmap to root deps"
[libs]
(reduce-kv
(fn [ret lib {:keys [dependents] :as coord}]
(if (seq dependents)
ret
(assoc ret lib coord)))
{} libs))
(defn meta-maven-path
[params]
(let [{:keys [lib]} params
pom-file (jio/file "META-INF" "maven" (namespace lib) (name lib))]
(.toString pom-file)))
(defn write-pom
[params]
(let [{:keys [basis class-dir target src-pom lib version scm src-dirs resource-dirs repos pom-data]} params
{:keys [libs]} basis
root-deps (libs->deps libs)
src-pom-file (when-not (= :none src-pom)
(api/resolve-path (or src-pom "pom.xml")))
repos (or repos (remove #(= "https://repo1.maven.org/maven2/" (-> % val :url)) (:mvn/repos basis)))
pom (if (and src-pom-file (.exists src-pom-file))
(do
(when pom-data
(println "Warning in write-pom: pom-data supplied but not used because pom template exists at" (or src-pom "pom.xml")))
(with-open [rdr (jio/reader src-pom-file)]
(-> rdr
parse-xml
(replace-deps root-deps)
(replace-paths src-dirs)
(replace-resources resource-dirs)
(replace-repos repos)
(replace-lib lib)
(replace-version version)
(replace-scm scm))))
(gen-pom
(cond->
{:deps root-deps
:src-paths src-dirs
:resource-paths resource-dirs
:repos repos
:group (namespace lib)
:artifact (name lib)}
version (assoc :version version)
scm (assoc :scm scm)
pom-data (assoc :pom-data pom-data))))
pom-dir-file (file/ensure-dir
(cond
class-dir (jio/file (api/resolve-path class-dir) (meta-maven-path {:lib lib}))
target (-> target api/resolve-path jio/file file/ensure-dir)
:else (throw (ex-info "write-pom requires either :class-dir or :target" {}))))]
(spit (jio/file pom-dir-file "pom.xml") (xml/indent-str pom))
(spit (jio/file pom-dir-file "pom.properties")
(str/join (System/lineSeparator)
["# Generated by org.clojure/tools.build"
(let [dtf (DateTimeFormatter/ofPattern "E MMM d HH:mm:ss 'UTC' u")
inst (or (some-> "SOURCE_DATE_EPOCH"
System/getenv
parse-long
Instant/ofEpochSecond)
(Instant/now))]
(str "# " (.format dtf (ZonedDateTime/ofInstant inst (ZoneId/of "Z")))))
(format "version=%s" version)
(format "groupId=%s" (namespace lib))
(format "artifactId=%s" (name lib))]))))
================================================
FILE: src/main/clojure/clojure/tools/build/tasks/zip.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.zip
(:require
[clojure.java.io :as jio]
[clojure.tools.build.api :as api]
[clojure.tools.build.util.file :as file]
[clojure.tools.build.util.zip :as zip])
(:import
[java.util.zip ZipOutputStream]))
(set! *warn-on-reflection* true)
(defn zip
[{:keys [src-dirs zip-file] :as params}]
(let [zip-file (api/resolve-path zip-file)]
(file/ensure-dir (.getParent zip-file))
(with-open [zos (ZipOutputStream. (jio/output-stream zip-file))]
(doseq [zpath src-dirs]
(let [zip-from (file/ensure-dir (api/resolve-path zpath))]
;(println "Zipping from" (.getPath zip-from) "to" (.getPath zip-file))
(zip/copy-to-zip zos zip-from))))))
(defn unzip
[{:keys [zip-file target-dir] :as params}]
(let [{:keys [zip-file target-dir]} params
ret (zip/unzip (api/resolve-path zip-file) (api/resolve-path target-dir))]
(when-not ret
(throw (ex-info (format "Zip file does not exist: %s" zip-file) {})))))
================================================
FILE: src/main/clojure/clojure/tools/build/util/file.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.util.file
(:require
[clojure.java.io :as jio]
[clojure.string :as str])
(:import
[java.io File]
[java.nio.file Path Files LinkOption CopyOption StandardCopyOption]
[clojure.lang PersistentQueue]))
(set! *warn-on-reflection* true)
(defn collect-files
"Recursively collect all paths under path, starting from root.
Options:
:dirs - whether to collect directories (default false)
:collect - function for whether to collect a path (default yes)"
[^File root & {:keys [dirs collect]
:or {dirs false
collect (constantly true)}}]
(when (.exists root)
(loop [queue (conj PersistentQueue/EMPTY root)
collected []]
(let [^File file (peek queue)]
(if file
(let [path (.toPath file)
is-dir (Files/isDirectory path (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
children (when is-dir (with-open [entries (Files/newDirectoryStream path)]
(mapv #(.toFile ^Path %) entries)))
collect? (and (if is-dir dirs true) (collect file))]
(recur (into (pop queue) children) (if collect? (conj collected file) collected)))
(when (seq collected) collected))))))
(defn suffixes
"Returns a predicate matching suffixes"
[& suffixes]
(apply some-fn
(map #(fn [^File f] (str/ends-with? (.toString f) ^String %)) suffixes)))
(defn delete
"Recursively delete file, where file is coerced with clojure.java.io/file"
[file]
(run! #(.delete ^File %) (reverse (collect-files (jio/file file) :dirs true))))
(def ^{:private true, :tag "[Ljava.nio.file.CopyOption;"}
copy-options
(into-array CopyOption [StandardCopyOption/COPY_ATTRIBUTES StandardCopyOption/REPLACE_EXISTING]))
(defn copy-file
"Copy file from src to target, retaining file attributes. Returns nil."
[^File src-file ^File target-file]
(.mkdirs target-file)
(Files/copy (.toPath src-file) (.toPath target-file) copy-options)
nil)
(defn copy-contents
"Copy files in src dir to target dir, optionally filtering by prefix paths"
([^File src-dir ^File target-dir]
(let [source-path (.toPath src-dir)
target-path (.toPath target-dir)
source-files (collect-files src-dir)]
;(println "source" (str source-path))
;(println "target" (str target-path))
;(println "source-files" (map str source-files))
(run!
(fn [^File f]
(let [p (.toPath f)
new-path (.resolve target-path (.relativize source-path p))]
;(println "copying" (str p) (str new-path))
(copy-file f (.toFile new-path))))
source-files)))
([^File src-dir ^File target-dir prefixes]
(when (.exists src-dir)
(let [root (.toPath src-dir)
target (.toPath target-dir)]
(loop [queue (conj PersistentQueue/EMPTY src-dir)]
(let [^File file (peek queue)]
(when file
(let [path (.toPath file)
relative (.relativize root path)]
;(println "consider" (.toString file) "match" (some #(str/starts-with? (.toString relative) %) prefixes) "dir" (Files/isDirectory path (into-array LinkOption [LinkOption/NOFOLLOW_LINKS])))
(cond
;; match, copy this file/dir
(some #(str/starts-with? (.toString relative) %) prefixes)
(let [end-path (.resolve target relative)]
(copy-contents file (.toFile end-path))
(recur (pop queue)))
;; no match, but continue looking in this directory if it could match later
(and
(Files/isDirectory path (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
(some #(str/starts-with? % (.toString relative)) prefixes))
(recur (into (pop queue)
(with-open [entries (Files/newDirectoryStream path)]
(mapv #(.toFile ^Path %) entries))))
;; work the queue
:else
(recur (pop queue)))))))))))
(defn ensure-dir
"Ensure dir exists by making all parent directories and return it"
^File [dir]
(let [d (jio/file dir)]
(if (.exists d)
d
(if (.mkdirs d)
d
(throw (ex-info (str "Can't create directory " dir) {}))))))
(defn ensure-file
([file] (ensure-file file ""))
([file contents & opts]
(let [file (jio/file file)
parent (.getParent file)]
(if (.exists (jio/file parent))
(apply spit file contents opts)
(do
(ensure-dir parent)
(apply spit file contents opts))))))
================================================
FILE: src/main/clojure/clojure/tools/build/util/log.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.util.log
(:require
[clojure.pprint :as pprint]))
(defmacro log
[verbose & msgs]
`(when ~verbose
(println ~@msgs)))
(defmacro log-map
[verbose m]
`(when ~verbose
(binding [*print-namespace-maps* false]
(pprint/pprint ~m))))
================================================
FILE: src/main/clojure/clojure/tools/build/util/zip.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.util.zip
(:require
[clojure.java.io :as jio]
[clojure.tools.build.util.file :as file]
[clojure.string :as str])
(:import
[java.io File InputStream OutputStream]
[java.nio.file Files LinkOption]
[java.nio.file.attribute BasicFileAttributes]
[java.util.zip ZipFile ZipInputStream ZipOutputStream ZipEntry]
[java.util.jar Manifest Attributes$Name]))
(set! *warn-on-reflection* true)
(defn- add-zip-entry
[^ZipOutputStream output-stream ^String path ^File file]
(let [dir (.isDirectory file)
attrs (Files/readAttributes (.toPath file) BasicFileAttributes ^"[Ljava.nio.file.LinkOption;" (into-array LinkOption []))
path (if (and dir (not (.endsWith path "/"))) (str path "/") path)
path (str/replace path \\ \/) ;; only use unix-style paths in jars
entry (doto (ZipEntry. path)
;(.setSize (.size attrs))
;(.setLastAccessTime (.lastAccessTime attrs))
(.setLastModifiedTime (.lastModifiedTime attrs)))]
(.putNextEntry output-stream entry)
(when-not dir
(with-open [fis (jio/input-stream file)]
(jio/copy fis output-stream)))
(.closeEntry output-stream)))
(defn copy-to-zip
[^ZipOutputStream jos ^File root]
(let [root-path (.toPath root)
files (file/collect-files root :dirs true)]
(run! (fn [^File f]
(let [rel-path (.toString (.relativize root-path (.toPath f)))]
(when-not (= rel-path "")
;(println " Adding" rel-path)
(add-zip-entry jos rel-path f))))
files)))
(defn fill-manifest!
[^Manifest manifest props]
(let [attrs (.getMainAttributes manifest)]
(run!
(fn [[name value]]
(.put attrs (Attributes$Name. ^String name) value)) props)))
(defn list-zip
[^String zip-path]
(let [zip-file (jio/file zip-path)]
(when (.exists zip-file)
(with-open [zip (ZipFile. zip-file)]
(let [entries (enumeration-seq (.entries zip))]
(sort-by :name
(into [] (map (fn [^ZipEntry entry]
{:name (.getName entry)
:created (.getCreationTime entry)
:modified (.getLastModifiedTime entry)
:size (.getSize entry)}))
entries)))))))
(defn copy-stream!
"Copy input stream to output stream using buffer.
Caller is responsible for passing buffered streams and closing streams."
[^InputStream is ^OutputStream os ^bytes buffer]
(loop []
(let [size (.read is buffer)]
(if (pos? size)
(do
(.write os buffer 0 size)
(recur))
(.close os)))))
(defn unzip
[^String zip-path ^String target-dir]
(let [buffer (byte-array 4096)
zip-file (jio/file zip-path)]
(if (.exists zip-file)
(with-open [zis (ZipInputStream. (jio/input-stream zip-file))]
(loop []
(if-let [entry (.getNextEntry zis)]
;(println "entry:" (.getName entry) (.isDirectory entry))
(let [out-file (jio/file target-dir (.getName entry))]
(jio/make-parents out-file)
(when-not (.isDirectory entry)
(with-open [output (jio/output-stream out-file)]
(copy-stream! zis output buffer)
(Files/setLastModifiedTime (.toPath out-file) (.getLastModifiedTime entry))))
(recur))
true)))
false)))
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_basis.clj
================================================
(ns clojure.tools.build.tasks.test-basis
(:require
[clojure.test :refer :all]
[clojure.tools.build.api :as api]
[clojure.tools.build.test-util :refer :all])
(:import
[java.nio.file Files]
[java.nio.file.attribute FileAttribute]))
(deftest test-missing-project-deps-file
(let [path (Files/createTempDirectory "abc" (make-array FileAttribute 0))]
(with-test-dir (.toString path)
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/create-basis {}))))
(comment
(run-tests)
)
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_compile_clj.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-compile-clj
(:require
[clojure.test :refer :all :as test]
[clojure.java.io :as jio]
[clojure.string :as str]
[clojure.tools.build.api :as api]
[clojure.tools.build.tasks.compile-clj :as compile-clj]
[clojure.tools.build.test-util :refer :all]))
(deftest test-topo
;; deps: a -> b -> c, d
;; expect: c b a (reverse topo sort), then d at the end
(is (= '[c b a d]
(#'compile-clj/nses-in-topo [(jio/file "test-data/nses/src")]))))
(deftest test-compile
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/compile-clj {:class-dir "target/classes"
:src-dirs ["src"]
:basis (api/create-basis nil)})
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar.class")))))
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar__init.class")))))
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar$hello.class")))))))
;; use :src-dirs from basis paths
(deftest test-compile-basis-paths
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/compile-clj {:class-dir "target/classes"
:basis (api/create-basis nil)})
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar.class")))))
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar__init.class")))))
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar$hello.class")))))))
(defn find-java []
(-> (api/process {:command-args [(if windows? "where" "which") "java"]
:out :capture})
:out
str/split-lines
first))
(deftest test-compile-passthrough-opts
(when-not (str/starts-with? (System/getProperty "java.version") "1.")
(let [java-cmd (find-java)]
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/compile-clj {:class-dir "target/classes"
:src-dirs ["src"]
:basis (api/create-basis nil)
;; pass these through to java command
:java-opts ["-Dhi=there"]
:use-cp-file :always
:java-cmd java-cmd})
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar.class")))))
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar__init.class")))))
(is (true? (.exists (jio/file (project-path "target/classes/foo/bar$hello.class")))))))))
(deftest test-turn-off-assert-with-bindings
(with-test-dir "test-data/assert"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(let [basis (api/create-basis nil)
invoke #(-> {:basis basis :main 'clojure.main :main-args ["-e" "((requiring-resolve 'foo.check-assert/f) 100)"]}
api/java-command
(merge {:out :capture, :err :ignore})
api/process)
compile-params {:class-dir "target/classes" :src-dirs ["src"] :basis basis}]
;; by default, assertions are on when compiling, then invocation fails (assertion expects keyword)
(api/compile-clj compile-params) ;; no :bindings set
(is (= {:exit 1} (invoke)))
;; recompile with binding to turn off assertions, then it passes (assertion not checked)
(api/delete {:path "target/classes"})
(api/compile-clj (assoc compile-params :bindings {#'clojure.core/*assert* false})) ;; turn off asserts
(is (= {:exit 0, :out (str "100" (System/lineSeparator))} (invoke))))))
(deftest test-capture-reflection
(with-test-dir "test-data/reflecting"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(let [basis (api/create-basis nil)
compile-params {:class-dir "target/classes"
:src-dirs ["src"]
:basis basis
:ns-compile ['foo.bar]}]
;; by default, reflection does not warn
(is (nil? (api/compile-clj compile-params))) ;; no :bindings set
;; compile with reflection warnings and capture the error output
(api/delete {:path "target/classes"})
(is (str/starts-with?
(:err
(api/compile-clj (merge compile-params
{:bindings {#'clojure.core/*warn-on-reflection* true}
:err :capture})))
"Reflection warning")))))
(deftest test-accidental-basis-delay
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(is (thrown? clojure.lang.ExceptionInfo
(api/compile-clj {:class-dir "target/classes"
:src-dirs ["src"]
:basis (delay (api/create-basis nil))})))))
(comment
(run-tests)
)
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_copy.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-copy
(:require
[clojure.test :refer :all]
[clojure.java.io :as jio]
[clojure.string :as str]
[clojure.tools.build.api :as api]
[clojure.tools.build.util.file :as file]
[clojure.tools.build.util.zip :as zip]
[clojure.tools.build.test-util :refer :all])
(:import
[java.io File FileInputStream ByteArrayOutputStream]
[java.nio.file Files LinkOption FileSystems]
[java.nio.file.attribute PosixFilePermission]
[java.util UUID]))
(defn slurp-binary
[^File f]
(let [fis (FileInputStream. f)
os (ByteArrayOutputStream.)
buffer (byte-array 4096)]
(zip/copy-stream! fis os buffer)
(.toByteArray os)))
(deftest test-copy
(with-test-dir "test-data/p1"
(let [txt (str (UUID/randomUUID))]
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/copy-dir {:target-dir "target/classes"
:src-dirs ["src" "resources"]
:replace {"__REPLACE__" txt}})
(let [source-file (jio/file (project-path "target/classes/foo/bar.clj"))
contents (slurp source-file)]
(is (.exists source-file))
(is (str/includes? contents txt)))
;; binary files in replaced exts should be copied but not replaced
(let [binary-in (jio/file (project-path "resources/test.png"))
binary-out (jio/file (project-path "target/classes/test.png"))]
(is (.exists binary-out))
(is (= (seq (slurp-binary binary-in)) (seq (slurp-binary binary-out))))))))
(deftest test-replace-retains-perms
(when (contains? (.supportedFileAttributeViews (FileSystems/getDefault)) "posix")
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(let [start-file (jio/file (project-path "target/x/f"))
_start (file/ensure-file start-file "abc")
start-path (.toPath start-file)]
(Files/setPosixFilePermissions start-path #{PosixFilePermission/OWNER_READ PosixFilePermission/GROUP_READ PosixFilePermission/OWNER_EXECUTE})
(api/copy-dir {:src-dirs [(project-path "target/x")] :target-dir (project-path "target/y") :replace {"abc" "xyz"}})
(let [end (jio/file (project-path "target/y/f"))
end-path (.toPath end)
perms (Files/getPosixFilePermissions end-path (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))]
(is (= (slurp end) "xyz"))
(is (contains? perms PosixFilePermission/OWNER_EXECUTE)))))))
(comment
(run-tests)
)
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_delete.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-delete
(:require
[clojure.test :refer :all :as test]
[clojure.java.io :as jio]
[clojure.tools.build.api :as api]
[clojure.tools.build.test-util :refer :all]))
(deftest test-delete
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
;; copy src into target, then delete, and check target dir is gone
(api/copy-dir {:target-dir "target/classes"
:src-dirs ["src"]})
(api/delete {:path "target"})
(is (false? (.exists (jio/file (project-path "target/classes")))))))
(comment
(run-tests)
)
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_install.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-install
(:require
[clojure.java.io :as jio]
[clojure.test :as test :refer [deftest is]]
[clojure.tools.build.api :as api]
[clojure.tools.build.test-util :refer [with-test-dir *test-dir* project-path]]))
(def test-org (str (gensym "ORG")))
(def test-lib (str (gensym "LIB")))
(def lib (symbol test-org test-lib))
(def version "1.0.0")
(deftest test-install-no-pom
(with-test-dir "test-data/p1"
(let [classes "target/classes"
jar-path "target/output.jar"
local-repo (project-path "tmp-repo")
basis (api/create-basis {:project "deps.edn", :extra {:mvn/local-repo local-repo}})]
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/copy-dir {:src-dirs ["src"], :target-dir classes})
(api/write-pom {:basis basis, :class-dir classes, :lib lib, :version version})
(api/jar {:class-dir classes, :jar-file jar-path})
(api/install {:basis basis
:jar-file jar-path
:lib lib
:class-dir classes
:version version})
(let [expected-dir (jio/file local-repo test-org)
expected-jar (jio/file expected-dir test-lib version (str test-lib "-1.0.0.jar"))
expected-pom (jio/file expected-dir test-lib version (str test-lib "-1.0.0.pom"))]
(is (.exists expected-dir))
(is (.exists expected-jar))
(is (.exists expected-pom))))))
(comment
(test/run-tests)
)
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_jar.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-jar
(:require
[clojure.string :as str]
[clojure.test :refer :all]
[clojure.java.io :as jio]
[clojure.tools.build.api :as api]
[clojure.tools.build.test-util :refer :all]
[clojure.tools.build.util.zip :as zip])
(:import [java.util.zip ZipFile ZipEntry]))
(defn slurp-manifest
[z]
(let [zip-file (jio/file z)]
(with-open [zip (ZipFile. zip-file)]
(let [^ZipEntry ze (.getEntry zip "META-INF/MANIFEST.MF")]
(when ze
(slurp (.getInputStream zip ze)))))))
(deftest test-jar
(let [jar-path "target/output.jar"]
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/jar {:class-dir "src"
:jar-file jar-path})
(is (true? (.exists (jio/file (project-path jar-path)))))
(is (= #{"META-INF/MANIFEST.MF" "foo/" "foo/bar.clj"}
(set (map :name (zip/list-zip (project-path jar-path)))))))))
(deftest test-jar-custom-manifest
(let [jar-path "target/output.jar"]
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/jar {:class-dir "src"
:jar-file jar-path
:manifest {"Abc" 100}})
(is (true? (.exists (jio/file (project-path jar-path)))))
(is (= #{"META-INF/MANIFEST.MF" "foo/" "foo/bar.clj"}
(set (map :name (zip/list-zip (project-path jar-path))))))
(let [manifest-out (slurp-manifest (project-path jar-path))]
(is (str/includes? manifest-out "Abc: 100"))))))
(comment
(run-tests)
)
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_javac.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-javac
(:require
[clojure.string :as str]
[clojure.test :refer :all :as test]
[clojure.java.io :as jio]
[clojure.tools.build.api :as api]
[clojure.tools.build.test-util :refer :all]))
(deftest test-javac
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/javac {:class-dir "target/classes"
:src-dirs ["java"]})
(is (true? (.exists (jio/file (project-path "target/classes/foo/Demo1.class")))))
(is (true? (.exists (jio/file (project-path "target/classes/foo/Demo2.class")))))
(let [class-path (.getPath (jio/file (project-path "target/classes")))]
(is (= "Hello" (str/trim (:out (api/process {:command-args ["java" "-cp" class-path "foo.Demo1"] :out :capture})))))
(is (= "Hello" (str/trim (:out (api/process {:command-args ["java" "-cp" class-path "foo.Demo2"] :out :capture}))))))))
(comment
(run-tests)
)
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_pom.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-pom
(:require
[clojure.test :refer :all :as test]
[clojure.java.io :as jio]
[clojure.string :as str]
[clojure.zip :as zip]
[clojure.data.xml :as xml]
[clojure.tools.build.api :as api]
[clojure.tools.build.tasks.write-pom :as write-pom]
[clojure.tools.build.test-util :refer :all])
(:import
[java.io File InputStream]
[java.util Properties]
[clojure.lang ExceptionInfo]))
(set! *warn-on-reflection* true)
(xml/alias-uri 'pom "http://maven.apache.org/POM/4.0.0")
(defn read-xml
[^File f]
(when (.exists f)
(#'write-pom/parse-xml (jio/reader f))))
(defn xml-path-val
[root tag-path]
(let [z (zip/zipper xml/element? :content nil root)]
(loop [[tag & more-tags :as tags] tag-path, parent z, child (zip/down z)]
(if child
(let [node (zip/node child)]
(if (= tag (:tag node))
(if (seq more-tags)
(recur more-tags child (zip/down child))
(:content node))
(recur tags parent (zip/right child))))
nil))))
(defn read-props
[^File f]
(let [props (Properties.)]
(when (.exists f)
(doto props
(.load ^InputStream (jio/input-stream f))))))
(deftest test-new-pom
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {;; NO :src-pom
:lib 'test/p1
:version "1.2.3"
:class-dir "target/classes"
:src-dirs ["src"]
:resource-dirs ["resources"]
:basis (api/create-basis nil)
:scm {:tag "v1.2.3" :url "https://github.com/example/p1"}})
(let [pom-dir (jio/file (project-path "target/classes/META-INF/maven/test/p1"))
pom-out (jio/file pom-dir "pom.xml")
pom (read-xml pom-out)
prop-out (jio/file pom-dir "pom.properties")
props (read-props prop-out)]
;; check xml out
(is (.exists pom-out))
(are [path val] (= val (xml-path-val pom path))
[::pom/packaging] ["jar"]
[::pom/groupId] ["test"]
[::pom/artifactId] ["p1"]
[::pom/version] ["1.2.3"]
[::pom/name] ["p1"]
[::pom/build ::pom/sourceDirectory] ["src"]
[::pom/build ::pom/resources ::pom/resource ::pom/directory] ["resources"]
[::pom/scm ::pom/tag] ["v1.2.3"]
[::pom/scm ::pom/url] ["https://github.com/example/p1"])
(is (= 2 (count (xml-path-val pom [::pom/dependencies]))))
(is (= 1 (count (xml-path-val pom [::pom/repositories]))))
;; check properties out
(is (.exists prop-out))
(is (submap? {"groupId" "test", "artifactId" "p1", "version" "1.2.3"} props)))))
(deftest test-update-existing-pom
(with-test-dir "test-data/p2"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {:lib 'test/p2
:version "1.2.3"
:class-dir "target/classes"
:src-dirs ["src"]
:src-pom "pom.xml"
:resource-dirs ["resources"]
:basis (api/create-basis nil)
:scm {:tag "v1.2.3"
:url "https://github.com/example/p1"}})
(let [pom-dir (jio/file (project-path "target/classes/META-INF/maven/test/p2"))
pom-out (jio/file pom-dir "pom.xml")
pom (read-xml pom-out)
prop-out (jio/file pom-dir "pom.properties")
props (read-props prop-out)]
;; check xml out
(is (.exists pom-out))
(are [path val] (= val (xml-path-val pom path))
[::pom/packaging] ["jar"]
[::pom/groupId] ["test"]
[::pom/artifactId] ["p2"]
[::pom/version] ["1.2.3"]
[::pom/name] ["p2"]
[::pom/build ::pom/sourceDirectory] ["src"]
[::pom/build ::pom/resources ::pom/resource ::pom/directory] ["resources"]
[::pom/scm ::pom/tag] ["v1.2.3"])
(is (= 2 (count (xml-path-val pom [::pom/dependencies]))))
(is (= 1 (count (xml-path-val pom [::pom/repositories]))))
;; check properties out
(is (.exists prop-out))
(is (submap? {"groupId" "test", "artifactId" "p2", "version" "1.2.3"} props)))))
(deftest test-ignore-existing-pom
;; verify existing scm info is preserved if src-pom is supplied:
(with-test-dir "test-data/p4"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {:lib 'test/p4
:version "1.2.3"
:class-dir "target/classes"
:src-dirs ["src"]
:src-pom "pom.xml"
:resource-dirs ["resources"]
:basis (api/create-basis nil)})
(let [pom-dir (jio/file (project-path "target/classes/META-INF/maven/test/p4"))
pom-out (jio/file pom-dir "pom.xml")
pom (read-xml pom-out)
prop-out (jio/file pom-dir "pom.properties")
props (read-props prop-out)]
;; check xml out
(is (.exists pom-out))
(are [path val] (= val (xml-path-val pom path))
[::pom/packaging] ["jar"]
[::pom/groupId] ["test"]
[::pom/artifactId] ["p4"]
[::pom/version] ["1.2.3"]
[::pom/name] ["p4"]
[::pom/build ::pom/sourceDirectory] ["src"]
[::pom/build ::pom/resources ::pom/resource ::pom/directory] ["resources"]
[::pom/scm ::pom/tag] ["HEAD"]
[::pom/scm ::pom/url] ["git@github.com:clojure/tools.build.git"])
(is (= 2 (count (xml-path-val pom [::pom/dependencies]))))
(is (= 1 (count (xml-path-val pom [::pom/repositories]))))
;; check properties out
(is (.exists prop-out))
(is (submap? {"groupId" "test", "artifactId" "p4", "version" "1.2.3"} props))))
;; verify no scm info is present if src-pom is :none:
(with-test-dir "test-data/p4"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {:lib 'test/p4
:version "1.2.3"
:class-dir "target/classes"
:src-dirs ["src"]
:src-pom :none
:resource-dirs ["resources"]
:basis (api/create-basis nil)})
(let [pom-dir (jio/file (project-path "target/classes/META-INF/maven/test/p4"))
pom-out (jio/file pom-dir "pom.xml")
pom (read-xml pom-out)
prop-out (jio/file pom-dir "pom.properties")
props (read-props prop-out)]
;; check xml out
(is (.exists pom-out))
(are [path val] (= val (xml-path-val pom path))
[::pom/packaging] ["jar"]
[::pom/groupId] ["test"]
[::pom/artifactId] ["p4"]
[::pom/version] ["1.2.3"]
[::pom/name] ["p4"]
[::pom/build ::pom/sourceDirectory] ["src"]
[::pom/build ::pom/resources ::pom/resource ::pom/directory] ["resources"]
[::pom/scm ::pom/tag] nil
[::pom/scm ::pom/url] nil)
(is (= 2 (count (xml-path-val pom [::pom/dependencies]))))
(is (= 1 (count (xml-path-val pom [::pom/repositories]))))
;; check properties out
(is (.exists prop-out))
(is (submap? {"groupId" "test", "artifactId" "p4", "version" "1.2.3"} props)))))
;; check that optional deps are marked optional
(deftest test-optional
(with-test-dir "test-data/p3"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {:lib 'test/p3
:version "1.2.3"
:class-dir "target/classes"
:src-dirs ["src"]
:src-pom "pom.xml"
:resource-dirs ["resources"]
:basis (api/create-basis nil)})
(let [pom-dir (jio/file (project-path "target/classes/META-INF/maven/test/p3"))
pom-out (jio/file pom-dir "pom.xml")]
(is (.exists pom-out))
(let [generated (slurp pom-out)]
(is (str/includes? generated "core.async"))
(is (str/includes? generated "<optional>true</optional>"))))))
;; check that supplying an empty repo map removes repos from generated pom
(deftest test-omit-repos
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {:lib 'test/p1
:version "1.2.3"
:class-dir "target/classes"
:src-dirs ["src"]
:src-pom "pom.xml"
:resource-dirs ["resources"]
:repos {} ;; replace repo map from deps.edn
:basis (api/create-basis nil)})
(let [pom-dir (jio/file (project-path "target/classes/META-INF/maven/test/p1"))
pom-out (jio/file pom-dir "pom.xml")]
(is (.exists pom-out))
(let [generated (slurp pom-out)]
(is (not (str/includes? generated "clojars")))))))
;; check that :extra-deps in basis aliases are reflected in pom deps
(deftest test-extra-deps
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {:lib 'test/p1
:version "1.2.3"
:class-dir "target/classes"
:src-dirs ["src"]
:src-pom "pom.xml"
:resource-dirs ["resources"]
:basis (api/create-basis '{:extra {:aliases {:ex {:extra-deps {org.clojure/data.json {:mvn/version "2.3.1"}}}}}
:aliases [:ex]})})
(let [pom-dir (jio/file (project-path "target/classes/META-INF/maven/test/p1"))
pom-out (jio/file pom-dir "pom.xml")]
(is (.exists pom-out))
(let [generated (slurp pom-out)]
(is (str/includes? generated "data.json"))))))
(deftest test-pom-path
(is (= (jio/file "META-INF/maven/a.b/c/pom.xml") (jio/file (api/pom-path {:lib 'a.b/c}))))
(let [prior api/*project-root*]
(api/set-project-root! ".")
(is (= (jio/file "./foo/META-INF/maven/a.b/c/pom.xml")
(jio/file (api/pom-path {:class-dir "foo" :lib 'a.b/c}))))
(api/set-project-root! prior)))
(deftest test-validate-lib
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(try
(api/write-pom {:lib 'unqualified-lib ;; invalid
:version "1.2.3"
:class-dir "target/classes"
:src-dirs ["src"]
:src-pom "pom.xml"
:resource-dirs ["resources"]
:basis (api/create-basis nil)})
(catch ExceptionInfo e
(let [m (ex-message e)]
(is (str/includes? m ":lib"))
(is (str/includes? m "unqualified-lib"))
(is (str/includes? m "qualified-ident?")))))))
(deftest test-target
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {:lib 'test/p1
:version "1.2.3"
:target "target/output-pom.xml"
:src-dirs ["src"]
:resource-dirs ["resources"]
:basis (api/create-basis nil)})
(is (.exists (jio/file (project-path "target/output-pom.xml"))))))
(deftest test-target-or-class-dir
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(try
(api/write-pom {:lib 'test/p1
:version "1.2.3"
;; NO :target or :class-dir
:src-dirs ["src"]
:src-pom "pom.xml"
:resource-dirs ["resources"]
:basis (api/create-basis nil)})
(is false)
(catch Throwable t
(is true)))))
(deftest test-pom-data
(with-test-dir "test-data/p1"
(api/set-project-root! (.getAbsolutePath *test-dir*))
(api/delete {:path "target"})
(api/write-pom {:lib 'test/p1
:version "1.2.3"
:target "target"
:src-dirs ["src"]
:resource-dirs ["resources"]
:basis (api/create-basis nil)
:pom-data [[:licenses
[:license
[:name "Apache-2.0"]
[:url "https://www.apache.org/licenses/LICENSE-2.0.txt"]
[:distribution "repo"]
[:comments "OSS license"]]]
[:foo
[:bar "hello"]]]})
(is (.exists (jio/file (project-path "target/pom.xml"))))
(let [written-pom (slurp (project-path "target/pom.xml"))]
(is (str/includes? written-pom "<name>Apache-2.0</name>"))
(is (str/includes? written-pom "<bar>hello</bar>")))))
(comment
(run-tests)
(test-validate-lib)
)
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_process.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-process
(:require
[clojure.test :refer :all]
[clojure.set :as set]
[clojure.tools.build.api :as api]
[clojure.tools.build.tasks.process :as process]))
(deftest test-large-process-output
(is (string? (api/git-process {:git-args ["log"]}))))
(deftest test-capture
(is (string? (:err (api/process {:command-args ["java" "-version"]
:err :capture})))))
(deftest test-env-and-capture
(when-not (#'process/windows?)
(is (= "hi\n"
(:out
(api/process {:env {"FOO" "hi"}
:command-args ["/bin/bash" "-c" "echo $FOO"]
:out :capture}))))))
(deftest test-need-cp-file
(let [f #'process/need-cp-file]
(are [os java length expected]
(= expected (f os java length))
"Windows 10" "9.0.1" 10000 true
"Windows 10" "9.0.1" 5000 false
"Windows 10" "1.8.0_261" 10000 false
"Mac OS X" "17" 10000 false)))
(deftest test-java-process-uses-and-merges-basis-jvm-opts
(let [basis (api/create-basis {:extra {:aliases {:opts {:jvm-opts ["-Dhi=there"]}}}
:aliases [:opts]})
command (api/java-command {:basis basis, :main 'clojure.main, :java-opts ["-Dfoo=bar"]})]
(is (set/subset? #{"-Dhi=there" "-Dfoo=bar"} (set (:command-args command))))))
================================================
FILE: src/test/clojure/clojure/tools/build/tasks/test_uber.clj
================================================
; Copyright (c) Rich Hickey. All rights reserved.
; The use and distribution terms for this software are covered by the
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
; which can be found in the file epl-v10.html at the root of this distribution.
; By using this software in any fashion, you are agreeing to be bound by
; the terms of this license.
; You must not remove this notice, or any other, from this software.
(ns clojure.tools.build.tasks.test-uber
(:require
[clojure.set :as set]
[clojure.string :as str]
[clojure.test :refer :all]
[clojure.java.io :as jio]
[clojure.tools.build.api :as api]
[clojure.tools.build.tasks.uber :as uber]
[clojure.tools.build.test-util :refer :all]
[clojure.tools.build.util.zip :as zip]
[clojure.tools.build.tasks.test-jar :as test-jar])
(:import
[clojure.lang ExceptionInfo]
[java.io ByteArrayInputS
gitextract_x3_0vtk6/
├── .clj-kondo/
│ └── config.edn
├── .github/
│ ├── PULL_REQUEST_TEMPLATE
│ └── workflows/
│ ├── build_docs.yml
│ ├── ci.yml
│ ├── release.yml
│ └── snapshot.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── deps.edn
├── docs/
│ ├── build.graffle
│ ├── clojure.tools.build.api.html
│ ├── css/
│ │ ├── default.css
│ │ └── highlight.css
│ ├── index.html
│ └── js/
│ └── page_effects.js
├── epl-v10.html
├── pom.xml
├── src/
│ ├── main/
│ │ └── clojure/
│ │ └── clojure/
│ │ └── tools/
│ │ └── build/
│ │ ├── api/
│ │ │ └── specs.clj
│ │ ├── api.clj
│ │ ├── tasks/
│ │ │ ├── compile_clj.clj
│ │ │ ├── copy.clj
│ │ │ ├── create_basis.clj
│ │ │ ├── install.clj
│ │ │ ├── jar.clj
│ │ │ ├── javac.clj
│ │ │ ├── process.clj
│ │ │ ├── uber.clj
│ │ │ ├── write_pom.clj
│ │ │ └── zip.clj
│ │ └── util/
│ │ ├── file.clj
│ │ ├── log.clj
│ │ └── zip.clj
│ └── test/
│ └── clojure/
│ └── clojure/
│ └── tools/
│ └── build/
│ ├── tasks/
│ │ ├── test_basis.clj
│ │ ├── test_compile_clj.clj
│ │ ├── test_copy.clj
│ │ ├── test_delete.clj
│ │ ├── test_install.clj
│ │ ├── test_jar.clj
│ │ ├── test_javac.clj
│ │ ├── test_pom.clj
│ │ ├── test_process.clj
│ │ ├── test_uber.clj
│ │ ├── test_write_file.clj
│ │ └── test_zip.clj
│ ├── test_project_root.clj
│ └── test_util.clj
└── test-data/
├── assert/
│ ├── deps.edn
│ └── src/
│ └── foo/
│ └── check_assert.clj
├── bad-zip/
│ ├── bad.jar
│ └── deps.edn
├── case-sensitive-collision/
│ ├── j1/
│ │ └── FOO
│ └── j2/
│ └── foo/
│ └── hi.txt
├── nses/
│ └── src/
│ ├── a.clj
│ ├── b.clj
│ ├── c.clj
│ └── d.clj
├── p1/
│ ├── deps.edn
│ ├── java/
│ │ └── foo/
│ │ ├── Demo1.java
│ │ └── Demo2.java
│ ├── resources/
│ │ └── data.edn
│ └── src/
│ └── foo/
│ └── bar.clj
├── p2/
│ ├── deps.edn
│ ├── pom.xml
│ ├── resources/
│ │ └── data.edn
│ └── src/
│ └── foo/
│ └── bar.clj
├── p3/
│ ├── deps.edn
│ ├── resources/
│ │ └── data.edn
│ └── src/
│ └── foo/
│ └── bar.clj
├── p4/
│ ├── deps.edn
│ ├── pom.xml
│ ├── resources/
│ │ └── data.edn
│ └── src/
│ └── foo/
│ └── bar.clj
├── reflecting/
│ ├── deps.edn
│ └── src/
│ └── foo/
│ └── bar.clj
└── uber-conflict/
├── j1/
│ ├── META-INF/
│ │ └── LICENSE.txt
│ ├── append.txt
│ ├── data_readers.clj
│ ├── data_readers.cljc
│ ├── ignore.txt
│ ├── my/
│ │ └── j1.txt
│ └── overwrite.txt
├── j2/
│ ├── META-INF/
│ │ └── LICENSE.txt
│ ├── append.txt
│ ├── data_readers.clj
│ ├── data_readers.cljc
│ ├── ignore.txt
│ ├── my/
│ │ └── j2.txt
│ └── overwrite.txt
└── j3/
└── META-INF/
└── LICENSE.txt
SYMBOL INDEX (16 symbols across 3 files)
FILE: docs/js/page_effects.js
function visibleInParent (line 1) | function visibleInParent(element) {
function hasFragment (line 6) | function hasFragment(link, fragment) {
function findLinkByFragment (line 10) | function findLinkByFragment(elements, fragment) {
function scrollToCurrentVarLink (line 14) | function scrollToCurrentVarLink(elements) {
function setCurrentVarLink (line 33) | function setCurrentVarLink() {
function scrollPositionId (line 47) | function scrollPositionId(element) {
function storeScrollPosition (line 52) | function storeScrollPosition(element) {
function recallScrollPosition (line 58) | function recallScrollPosition(element) {
function persistScrollPosition (line 64) | function persistScrollPosition(element) {
function sidebarContentWidth (line 69) | function sidebarContentWidth(element) {
function calculateSize (line 74) | function calculateSize(width, snap, margin, minimum) {
function resizeSidebars (line 83) | function resizeSidebars() {
FILE: test-data/p1/java/foo/Demo1.java
class Demo1 (line 3) | public class Demo1 {
method main (line 5) | public static void main(String[] args) {
FILE: test-data/p1/java/foo/Demo2.java
class Demo2 (line 3) | public class Demo2 {
method main (line 5) | public static void main(String[] args) {
Condensed preview — 92 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (227K chars).
[
{
"path": ".clj-kondo/config.edn",
"chars": 119,
"preview": "{:skip-comments true\n :linters\n {:unused-binding {:level :off}\n :cond-else {:level :off}\n :refer-all {:level :off}}}\n"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE",
"chars": 705,
"preview": "Hi! Thanks for your interest in contributing to this project.\n\nClojure contrib projects do not use GitHub issues or pull"
},
{
"path": ".github/workflows/build_docs.yml",
"chars": 1113,
"preview": "name: Build Docs\n\npermissions:\n contents: write\n\non:\n workflow_dispatch:\n\njobs:\n\n build:\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/ci.yml",
"chars": 840,
"preview": "name: Tests\n\npermissions:\n contents: read\n\non: [push]\n\njobs:\n test:\n strategy:\n matrix:\n java-version: "
},
{
"path": ".github/workflows/release.yml",
"chars": 562,
"preview": "name: Release on demand\n\npermissions:\n contents: write\n\non:\n workflow_dispatch:\n inputs:\n releaseVersion:\n "
},
{
"path": ".github/workflows/snapshot.yml",
"chars": 191,
"preview": "name: Snapshot on demand\n\npermissions:\n contents: read\n\non: [workflow_dispatch]\n\njobs:\n call-snapshot:\n uses: cloju"
},
{
"path": ".gitignore",
"chars": 159,
"preview": "*.iml\n.idea/\ntarget/\n.nrepl*\n.cpcache\n.lein*\n.java-version\nproject.clj\nout*\ntest-out\n.clj-kondo/.cache\n.vscode\n.lsp\n.cal"
},
{
"path": "CHANGELOG.md",
"chars": 7701,
"preview": "Changelog\n===========\n\n* v0.10.13 ae52edf on Mar 16, 2026\n * Update to latest tools.deps\n* v0.10.12 97c5562 on Jan 5, 2"
},
{
"path": "CONTRIBUTING.md",
"chars": 480,
"preview": "This is a [Clojure contrib] project.\n\nUnder the Clojure contrib [guidelines], this project cannot accept\npull requests. "
},
{
"path": "LICENSE",
"chars": 11516,
"preview": "Eclipse Public License - v 1.0\n\nTHE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC\nLICENSE (\"AG"
},
{
"path": "README.md",
"chars": 1403,
"preview": "tools.build\n========================================\n\nA library for building artifacts in Clojure projects.\n\n## Docs\n\n* "
},
{
"path": "deps.edn",
"chars": 1509,
"preview": "{:paths [\"src/main/clojure\" \"src/main/resources\"]\n\n :deps\n {org.clojure/clojure {:mvn/version \"1.12.4\"}\n org.clojure/to"
},
{
"path": "docs/clojure.tools.build.api.html",
"chars": 23263,
"preview": "<!DOCTYPE html PUBLIC \"\"\n \"\">\n<html><head><meta charset=\"UTF-8\" /><title>clojure.tools.build.api documentation</title"
},
{
"path": "docs/css/default.css",
"chars": 7859,
"preview": "body {\n font-family: Helvetica, Arial, sans-serif;\n font-size: 15px;\n}\n\npre, code {\n font-family: Monaco, DejaV"
},
{
"path": "docs/css/highlight.css",
"chars": 1146,
"preview": "/*\ngithub.com style (c) Vasily Polovnyov <vast@whiteants.net>\n*/\n\n.hljs {\n display: block;\n overflow-x: auto;\n paddin"
},
{
"path": "docs/index.html",
"chars": 3255,
"preview": "<!DOCTYPE html PUBLIC \"\"\n \"\">\n<html><head><meta charset=\"UTF-8\" /><title> </title><link rel=\"stylesheet\" type=\"text/c"
},
{
"path": "docs/js/page_effects.js",
"chars": 3528,
"preview": "function visibleInParent(element) {\n var position = $(element).position().top\n return position > -50 && position <"
},
{
"path": "epl-v10.html",
"chars": 12656,
"preview": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www."
},
{
"path": "pom.xml",
"chars": 4006,
"preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
},
{
"path": "src/main/clojure/clojure/tools/build/api/specs.clj",
"chars": 310,
"preview": "(ns clojure.tools.build.api.specs\n (:require [clojure.spec.alpha :as s]))\n\n(s/def ::lib qualified-ident?)\n(s/def ::path"
},
{
"path": "src/main/clojure/clojure/tools/build/api.clj",
"chars": 22703,
"preview": "(ns clojure.tools.build.api\n (:require\n [clojure.java.io :as jio]\n [clojure.set :as set]\n [clojure.spec.alpha "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/compile_clj.clj",
"chars": 5476,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/copy.clj",
"chars": 3880,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/create_basis.clj",
"chars": 1248,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/install.clj",
"chars": 1682,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/jar.clj",
"chars": 1574,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/javac.clj",
"chars": 1785,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/process.clj",
"chars": 6930,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/uber.clj",
"chars": 12070,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/write_pom.clj",
"chars": 10784,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/tasks/zip.clj",
"chars": 1469,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/util/file.clj",
"chars": 5182,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/util/log.clj",
"chars": 744,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/main/clojure/clojure/tools/build/util/zip.clj",
"chars": 3953,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_basis.clj",
"chars": 529,
"preview": "(ns clojure.tools.build.tasks.test-basis\n (:require\n [clojure.test :refer :all]\n [clojure.tools.build.api :as api"
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_compile_clj.clj",
"chars": 5367,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_copy.clj",
"chars": 2994,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_delete.clj",
"chars": 1077,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_install.clj",
"chars": 1963,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_jar.clj",
"chars": 2052,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_javac.clj",
"chars": 1421,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_pom.clj",
"chars": 13610,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_process.clj",
"chars": 1836,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_uber.clj",
"chars": 11319,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_write_file.clj",
"chars": 1737,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/tasks/test_zip.clj",
"chars": 2196,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "src/test/clojure/clojure/tools/build/test_project_root.clj",
"chars": 810,
"preview": "(ns clojure.tools.build.test-project-root\n (:require\n [clojure.java.io :as jio]\n [clojure.test :refer :all]\n [clo"
},
{
"path": "src/test/clojure/clojure/tools/build/test_util.clj",
"chars": 1383,
"preview": "; Copyright (c) Rich Hickey. All rights reserved.\n; The use and distribution terms for this software are covered by "
},
{
"path": "test-data/assert/deps.edn",
"chars": 89,
"preview": "{:paths [\"target/classes\" \"src\"]\n\n :deps\n {org.clojure/clojure {:mvn/version \"1.10.3\"}}}\n"
},
{
"path": "test-data/assert/src/foo/check_assert.clj",
"chars": 66,
"preview": "(ns foo.check-assert)\n\n(defn f\n [x]\n {:pre [(keyword? x)]}\n x)\n"
},
{
"path": "test-data/bad-zip/deps.edn",
"chars": 41,
"preview": "{:deps {my/bad {:local/root \"bad.jar\"}}}\n"
},
{
"path": "test-data/case-sensitive-collision/j1/FOO",
"chars": 10,
"preview": "I'm a foo\n"
},
{
"path": "test-data/case-sensitive-collision/j2/foo/hi.txt",
"chars": 3,
"preview": "hi\n"
},
{
"path": "test-data/nses/src/a.clj",
"chars": 21,
"preview": "(ns a\n (:require b))"
},
{
"path": "test-data/nses/src/b.clj",
"chars": 21,
"preview": "(ns b\n (:require c))"
},
{
"path": "test-data/nses/src/c.clj",
"chars": 6,
"preview": "(ns c)"
},
{
"path": "test-data/nses/src/d.clj",
"chars": 6,
"preview": "(ns d)"
},
{
"path": "test-data/p1/deps.edn",
"chars": 208,
"preview": "{:paths [:clj-paths :resource-paths]\n\n :deps\n {org.clojure/clojure {:mvn/version \"1.10.1\"}\n org.clojure/core.cache {:mv"
},
{
"path": "test-data/p1/java/foo/Demo1.java",
"chars": 118,
"preview": "package foo;\n\npublic class Demo1 {\n\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}\n"
},
{
"path": "test-data/p1/java/foo/Demo2.java",
"chars": 118,
"preview": "package foo;\n\npublic class Demo2 {\n\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}\n"
},
{
"path": "test-data/p1/resources/data.edn",
"chars": 22,
"preview": "{:version \"$version\"}\n"
},
{
"path": "test-data/p1/src/foo/bar.clj",
"chars": 114,
"preview": "(ns foo.bar\n \"__REPLACE__\"\n (:gen-class))\n\n(defn hello [] (println \"hello\"))\n\n(defn -main\n [& args]\n (hello))\n"
},
{
"path": "test-data/p2/deps.edn",
"chars": 208,
"preview": "{:paths [:clj-paths :resource-paths]\n\n :deps\n {org.clojure/clojure {:mvn/version \"1.10.1\"}\n org.clojure/core.cache {:mv"
},
{
"path": "test-data/p2/pom.xml",
"chars": 494,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "test-data/p2/resources/data.edn",
"chars": 22,
"preview": "{:version \"$version\"}\n"
},
{
"path": "test-data/p2/src/foo/bar.clj",
"chars": 48,
"preview": "(ns foo.bar)\n\n(defn hello [] (println \"hello\"))\n"
},
{
"path": "test-data/p3/deps.edn",
"chars": 223,
"preview": "{:paths [:clj-paths :resource-paths]\n\n :deps\n {org.clojure/clojure {:mvn/version \"1.10.1\"}\n org.clojure/core.async {:mv"
},
{
"path": "test-data/p3/resources/data.edn",
"chars": 22,
"preview": "{:version \"$version\"}\n"
},
{
"path": "test-data/p3/src/foo/bar.clj",
"chars": 48,
"preview": "(ns foo.bar)\n\n(defn hello [] (println \"hello\"))\n"
},
{
"path": "test-data/p4/deps.edn",
"chars": 208,
"preview": "{:paths [:clj-paths :resource-paths]\n\n :deps\n {org.clojure/clojure {:mvn/version \"1.10.1\"}\n org.clojure/core.cache {:mv"
},
{
"path": "test-data/p4/pom.xml",
"chars": 755,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "test-data/p4/resources/data.edn",
"chars": 22,
"preview": "{:version \"$version\"}\n"
},
{
"path": "test-data/p4/src/foo/bar.clj",
"chars": 48,
"preview": "(ns foo.bar)\n\n(defn hello [] (println \"hello\"))\n"
},
{
"path": "test-data/reflecting/deps.edn",
"chars": 72,
"preview": "{:paths [\"src\"]\n :deps\n {org.clojure/clojure {:mvn/version \"1.12.0\"}}\n}\n"
},
{
"path": "test-data/reflecting/src/foo/bar.clj",
"chars": 103,
"preview": "(ns foo.bar\n (:gen-class))\n\n(defn foo [s] (.length s))\n\n(defn -main [& args]\n (println (foo \"abc\")))\n"
},
{
"path": "test-data/uber-conflict/j1/META-INF/LICENSE.txt",
"chars": 45,
"preview": "this is a dummy license\nthat will be appended"
},
{
"path": "test-data/uber-conflict/j1/append.txt",
"chars": 3,
"preview": "j1\n"
},
{
"path": "test-data/uber-conflict/j1/data_readers.clj",
"chars": 47,
"preview": "{j1a my.foo/j1a-reader\n j1b my.bar/j1b-reader}\n"
},
{
"path": "test-data/uber-conflict/j1/data_readers.cljc",
"chars": 130,
"preview": "{j1a #?(:cljs my.cljs.foo/j1a-reader :clj my.clj.foo/j1a-reader)\n j1b #?(:cljs my.cljs.foo/j1b-reader :clj my.clj.foo/j1"
},
{
"path": "test-data/uber-conflict/j1/ignore.txt",
"chars": 8,
"preview": "j1 file\n"
},
{
"path": "test-data/uber-conflict/j1/my/j1.txt",
"chars": 8,
"preview": "j1 file\n"
},
{
"path": "test-data/uber-conflict/j1/overwrite.txt",
"chars": 8,
"preview": "j1 file\n"
},
{
"path": "test-data/uber-conflict/j2/META-INF/LICENSE.txt",
"chars": 50,
"preview": "this is a different license\nso should be included\n"
},
{
"path": "test-data/uber-conflict/j2/append.txt",
"chars": 3,
"preview": "j2\n"
},
{
"path": "test-data/uber-conflict/j2/data_readers.clj",
"chars": 47,
"preview": "{j2a my.foo/j2a-reader\n j2b my.bar/j2b-reader}\n"
},
{
"path": "test-data/uber-conflict/j2/data_readers.cljc",
"chars": 130,
"preview": "{j2a #?(:cljs my.cljs.foo/j2a-reader :clj my.clj.foo/j2a-reader)\n j2b #?(:cljs my.cljs.foo/j2b-reader :clj my.clj.foo/j2"
},
{
"path": "test-data/uber-conflict/j2/ignore.txt",
"chars": 8,
"preview": "j2 file\n"
},
{
"path": "test-data/uber-conflict/j2/my/j2.txt",
"chars": 8,
"preview": "j2 file\n"
},
{
"path": "test-data/uber-conflict/j2/overwrite.txt",
"chars": 8,
"preview": "j2 file\n"
},
{
"path": "test-data/uber-conflict/j3/META-INF/LICENSE.txt",
"chars": 45,
"preview": "this is a dummy license\nthat will be appended"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the clojure/tools.build GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 92 files (208.7 KB), approximately 60.4k tokens, and a symbol index with 16 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.