pax_global_header00006660000000000000000000000064134353556450014527gustar00rootroot0000000000000052 comment=f3864bc35d8280a8461b7f6c593b1919a75bef7f leiningen-2.9.1/000077500000000000000000000000001343535564500135105ustar00rootroot00000000000000leiningen-2.9.1/.circleci/000077500000000000000000000000001343535564500153435ustar00rootroot00000000000000leiningen-2.9.1/.circleci/config.yml000066400000000000000000000011001343535564500173230ustar00rootroot00000000000000version: 2 jobs: build: working_directory: ~/leiningen docker: # somehow docker hub deleted the 2.8.1 image?! # https://circleci.com/gh/technomancy/leiningen/1584 - image: clojure:lein-2.8.0 steps: - checkout - restore_cache: key: << checksum "project.clj" >> - run: working_directory: ~/leiningen/leiningen-core command: lein bootstrap - run: bin/lein test - save_cache: paths: - $HOME/.m2 - $HOME/.lein key: << checksum "project.clj" >> leiningen-2.9.1/.gitattributes000066400000000000000000000001341343535564500164010ustar00rootroot00000000000000#disable autocrlf for all .bat files since they already have CRLF in raw format *.bat -crlf leiningen-2.9.1/.github/000077500000000000000000000000001343535564500150505ustar00rootroot00000000000000leiningen-2.9.1/.github/ISSUE_TEMPLATE/000077500000000000000000000000001343535564500172335ustar00rootroot00000000000000leiningen-2.9.1/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000037411343535564500217320ustar00rootroot00000000000000--- name: Bug Report about: Create a report to help us improve --- **Initial debugging steps** Before creating a report, _especially_ around exceptions being thrown when running Leiningen, please check if the error still occurs after: - [ ] Updating to using the latest released version of Leiningen (`lein upgrade`). - [ ] Moving your `~/.lein/profiles.clj` (if present) out of the way. This contains third-party dependencies and plugins that can cause problems inside Leiningen. - [ ] Updating any old versions of plugins in your `project.clj`, especially if the problem is with a plugin not working. Old versions of plugins like nREPL and CIDER (as well as others) can cause problems with newer versions of Leiningen. - [ ] (If you are using Java 9 or newer), updating your dependencies to their most recent versions. Recent JDK's have introduced changes which can break some Clojure libraries. **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Run the command '...' 3. See error **Actual behavior** What actually happened? **Expected behavior** A clear and concise description of what you expected to happen. **Link to sample project** If relevant, please provide a link to a project or a `project.clj` that others can use to help debug the issue. **Logs** If applicable, add logs to help explain your problem, including the command that you ran. If the logs are very large, please put them in a [gist](https://gist.github.com/). **Environment** - Leiningen Version: [e.g. 2.9.0]. Get this by running `lein version`. - Leiningen installation method: [e.g. Homebrew, apt, manual]. - JDK Version: [e.g. openjdk version "11.0.1"]. Get this by running `java -version`. - OS: [e.g. Ubuntu 18.04, macOS 10.14]. - Anything else that might be relevant to your problem? **Additional context** Add any other context you have about the problem here. Did this work previously on older versions of Leiningen, or older JDK's? leiningen-2.9.1/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000001061343535564500227550ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project --- leiningen-2.9.1/.github/ISSUE_TEMPLATE/issue.md000066400000000000000000000000621343535564500207030ustar00rootroot00000000000000--- name: Standard issue about: Anything else --- leiningen-2.9.1/.gitignore000066400000000000000000000005331343535564500155010ustar00rootroot00000000000000**/target *.bak *.swp *.class *asc *jar *~ .lein* /.classpath /.nrepl-port /.project /.settings /hs_err_pid*.log /lein.man /leiningen-core/.lein-plugins/checksum /leiningen-core/.nrepl-port /leiningen-core/dev-resources/target /lein-pprint/.nrepl-port /logs /scratch.clj /target /web /wiki TAGS test_projects/*/target pom.xml deps.txt profiles.cljleiningen-2.9.1/CONTRIBUTING.md000066400000000000000000000117271343535564500157510ustar00rootroot00000000000000# Contributing Leiningen is the most widely-contributed-to Clojure project. We welcome potential contributors and do our best to try to make it easy to help out. Contributors who have had a single patch accepted may request commit rights as well as two free [stickers](http://hypirion.com/imgs/lein-stickers.jpg). Discussion occurs both in the [#leiningen channel on Freenode](irc://chat.freenode.net#leiningen) and on the [mailing list](http://www.freelists.org/list/leiningen). To join the mailing list, email [`leiningen-request@freelists.org`](mailto:leiningen-request@freelists.org?subject=subscribe) with `subscribe` in the Subject field, then follow the instructions in the reply you receive. The address `leiningen@freelists.org` is used for posting once you've joined. Please report issues on the [GitHub issue tracker](https://github.com/technomancy/leiningen/issues) or the mailing list. Sending bug reports to personal email addresses is inappropriate. Simpler issues appropriate for first-time contributors looking to help out are tagged "newbie". Code submissions should be [sent](https://man.sr.ht/git.sr.ht/send-email.md) with `git send-email` or as GitHub pull requests. Please use topic branches when sending pull requests rather than committing directly to master in order to minimize unnecessary merge commit clutter. Direct pull requests towards the master branch, not the stable branch. Leiningen is [mirrored at GitLab](https://gitlab.com/technomancy/leiningen) and [tested on CircleCI](https://circleci.com/gh/technomancy/leiningen). ## Codebase The definitions of the various tasks reside in `src/leiningen` in the top-level project. The underlying mechanisms for things like `project.clj` parsing, classpath calculation, and subprocess launching are implemented inside the `leiningen-core` subproject. See the [readme for the leiningen-core library](https://github.com/technomancy/leiningen/blob/master/leiningen-core/README.md) and `doc/PLUGINS.md` for more details on how Leiningen's codebase is structured. Try to be aware of the conventions in the existing code, except the one where we don't write tests. Make a reasonable attempt to avoid lines longer than 80 columns or function bodies longer than 20 lines. Don't use `when` unless it's for side-effects. Don't introduce new protocols. Use `^:internal` metadata to mark vars which can't be private but shouldn't be considered part of the public API. ## Bootstrapping You don't need to "build" Leiningen per se, but when you're developing on a checkout you will need to get its dependencies in place and compile some of the tasks. Assuming you are in Leiningen's project root, you can do that like this: ```bash $ cd leiningen-core $ lein bootstrap # or lein.bat on Windows. ``` The `lein` command is a stable release of Leiningen on your `$PATH` – preferably the newest one. If you don't have a stable `lein` installed, simply check out the `stable` branch and copy `bin/lein` to somewhere on your `$PATH`, then switch your branch back. If you want to use your development copy for everyday usage, symlink `bin/lein` to somewhere on your `$PATH`. You'll want to rename your stable installation to keep them from interfering; typically you can name that `lein2` or `lein-stable`. When dependencies in Leiningen change, you may have to do `rm .lein-classpath` in the project root, though in most cases this will be done automatically. If dependencies in leiningen-core change, you have to redo the `lein bootstrap` step mentioned earlier. Using `bin/lein` alone from the master branch without a full checkout is not supported. If you want to just grab a shell script to work with, use the `stable` branch. ### Uberjar from Master Since a development version is not uberjared, it can be rather slow compared to a stable release. If this is annoying and you depend on a recent fix or enhancement, you can build an uberjar from master as follows: ```bash # NB! You have to use *bin*/lein to build the uberjar $ bin/lein uberjar # ^ Last line printed from this command will tell the location of the standalone $ cp target/leiningen-2.5.2-SNAPSHOT-standalone.jar $HOME/.lein/self-installs $ cp bin/lein $HOME/bin/lein-master ``` Here, 2.5.2-SNAPSHOT is the version we've built, and we have `$HOME/bin` on our $PATH. Note that changes on master won't be visible in the uberjared version unless you overwrite both the lein script and a freshly created uberjar. ## Tests Before you're asking for a pull request, we would be very happy if you ensure that the changes you've done doesn't break any of the existing test cases. While there is a test suite, it's not terribly thorough, so don't put too much trust in it. Patches which add test coverage for the functionality they change are especially welcome. To run the test cases, run `bin/lein test` in the root directory: This will test both `leiningen-core` and `leiningen` itself. Do not attempt to run the tests with a stable version of Leiningen, as the namespaces conflict and you may end up with errors during the test run. leiningen-2.9.1/COPYING000066400000000000000000000763531343535564500145610ustar00rootroot00000000000000Source code distributed under the 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. Images distributed under the Creative Commons Attribution + ShareAlike License version 3.0: THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined below) for the purposes of this License. "Creative Commons Compatible License" means a license that is listed at http://creativecommons.org/compatiblelicenses that has been approved by Creative Commons as being essentially equivalent to this License, including, at a minimum, because that license: (i) contains terms that have the same purpose, meaning and effect as the License Elements of this License; and, (ii) explicitly permits the relicensing of adaptations of works made available under that license under this License or a Creative Commons jurisdiction license with the same License Elements as this License. "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; to Distribute and Publicly Perform the Work including as incorporated in Collections; and, to Distribute and Publicly Perform Adaptations. For the avoidance of doubt: Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. You may Distribute or Publicly Perform an Adaptation only under the terms of: (i) this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible License. If you license the Adaptation under one of the licenses mentioned in (iv), you must comply with the terms of that license. If you license the Adaptation under the terms of any of the licenses mentioned in (i), (ii) or (iii) (the "Applicable License"), you must comply with the terms of the Applicable License generally and the following provisions: (I) You must include a copy of, or the URI for, the Applicable License with every copy of each Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License; (III) You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Ssection 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. leiningen-2.9.1/NEWS.md000066400000000000000000001217011343535564500146100ustar00rootroot00000000000000# Leiningen News -- history of user-visible changes ## 2.9.1 / 2019-02-26 * Fix a bug where provided namespace compilation order was overridden. (Phil Hagelberg) * Don't emit namespaced maps when merging data readers for uberjar. (Joel Kaasinen) ## 2.9.0 / 2019-02-10 * Re-enable bootclasspath optimization by default. (Phil Hagelberg) * Sort namespace order consistently during AOT. (Logan Girard) * Use Clojure 1.10.0 for plugins and new templates projects. (Alex Miller, Phil Hagelberg) ## 2.8.3 / 2018-12-14 * Fix a warning in the powershell script. (Florian Anderiasch) * Fix a bug where the repl wouldn't launch. (Bozhidar Batsov) * Remove broken unattended GPG deploy feature. * Fix a bug where the repl didn't use `:main` as the initial ns. (Phil Hagelberg) ## 2.8.2 / 2018-12-11 * Fix a bug where hidden files would be included in jars. (James Elliott) * Add support for repository-overrides.clj to bootstrap repository info. (Greg Haskins) * Use stderr consistently for diagnostics. (Rob Browning) * Fix a bug in aliases that come from profiles. (Arnout Roemers) * Fix TLS errors in self-install on Windows. (Florian Anderiasch) * Templates use EPL-2.0 with GPL secondary license. (Yegor Timoshenko) * Allow GPG to be invoked unattended with passphrase. (Neil Okamoto) * Add pprint `--not-pretty` argument that prints instead of pprinting. (Rob Browning) * Always send diagnostic messages to standard error. (Rob Browning) * Add project coordinate data to jar metadata. (Conor McDermottroe) * Allow freeform `:pom-plugin` configuration. (Hannu Hartikainen) * **(Breaking)** Switch to [nREPL 0.5](https://metaredux.com/posts/2018/10/29/nrepl-redux.html). See the [upgrade notes](https://nrepl.org/nrepl/installation.html#upgrading) if you experience any problems with the `lein repl` task. (Bozhidar Batsov) ## 2.8.1 / 2017-10-27 * Fix a bug where `lein help` couldn't list built-in tasks on Java 9. (Phil Hagelberg) * Fix a bug where `lein` installed from package managers would obscure exit code. (Phil Hagelberg) * Fix an errant reflection warning on Java 9. (Toby Crawley) * Fix an error when no `:plugins` are specified. (Phil Hagelberg) * Fix a bug where launching project subprocesses would encounter unreadable forms. (Phil Hagelberg) * Remove auto-setting of cgroups memory limit. (Florian Anderiasch) ## 2.8.0 / 2017-10-17 * Support `LEIN_USE_BOOTCLASSPATH` for users on Java 8. (Phil Hagelberg) * Disable bytecode verification in Leiningen's own JVM for Java 9 compatibility. (Ghadi Shayban) * Infer values for pom `` tag from `.git` directory. (Nicolas Berger) ## 2.8.0-RC1 / 2017-09-18 * Project middleware, hooks, and the `:test` profile are considered deprecated. (Phil Hagelberg) * Help output no longer includes TOC output. (Irina Renteria) * The `vcs` task allows the commit message to be customized. (Toby Crawley) * JVMs on 8u131 and newer will default to using cgroups settings for memory limits. (Phil Hagelberg) * Add `:query` subcommand to `deps` to quickly find latest versions. (Phil Hagelberg) * Fix a bug where dependency resolution wasn't cached correctly. (Phil Hagelberg) * Support for HTTP nREPL has been moved out; requires drawbridge plugin now. (Phil Hagelberg) * Warn when `$CLASSPATH` is set. (Phil Hagelberg) * Default to requiring TLS for remote repositories. (Phil Hagelberg) * Remove warning when running as root. (Phil Hagelberg) * Add `:why` subtask to `deps` for tracing individual deps. (Phil Hagelberg) * Remove clj-http and cheshire dependencies, reducing likelihood of conflict. (Phil Hagelberg) * Warn when plugin dependencies conflict with Leiningen's own. (Phil Hagelberg) * Fix a bug where repls outside a project were not run in Leiningen's own process. (Phil Hagelberg) * Add `:plugin-tree` and `:tree-data` subtasks to `deps`. (Ken Restivo) * Support skipping bootclasspath for Java 9 compatibility. (Phil Hagelberg) * Allow `vcs` task to skip signing tags. (Nicolas Berger) * The `search` task no longer downloads indices but hits live search APIs. (Phil Hagelberg) * Remove duplicate exclusions in `lein deps`. (Emlyn Corrin) * Leiningen is now installable again via chocolatey. (Florian Anderiasch) * Dependency names can be specified as strings in addition to symbols. (Wes Morgan) ## 2.7.1 / 2016-09-22 * Add support for SDKMAN! as installation alternative. (Jean Niklas L'orange) * Improved explanation in some errors. (Jean Niklas L'orange) * Don't require `nil` for version in managed deps. (Chris Price) * Fix a bug with snapshot dependencies for managed deps. (Chris Price) ## 2.7.0 / 2016-08-24 * Add PowerShell script for Windows users. (Brian Lalonde) * Run `:prep-tasks` before `lein test`, so generated test namespaces will be tested. (Martin Reck) * Better error message when attempting to do `lein run` without `project.clj`. (Eduardo Seabra Silva) * Add support for `:managed-dependencies`. (Chris Price) * Provide the current clojars certificate. (Toby Crawley) * Add `*eval-print-dup*` to evaluate forms passed to `eval-in-leiningen` with `*print-dup*`. (Eduardo Seabra Silva) * Update bash completions. (Zack Dever) * Respect `:scm :dir` in `lein vcs` commands. (Ian Kerins) * Improve whitespace handling from `JVM_OPTS`. (Stephen Nelson) * Catch and handle fixture errors during `lein test`. (Alex Hall) * Fix a bug where spaces in directory names on Windows caused crashes. (Leon Mergen, Tobias Kiertscher, Jean Niklas L'orange) * Fix a bug where `lein search` would take forever downloading clojars.org. (Paul Dorman) * Retain user defined private repositories when building jars, uberjars and deploy. (Rick Moynihan) * Honor whitelist settings when `lein javac` is called via `lein jar`. (Chris Price) * `lein vsc push` for git will now only push branch-related tags. (Łukasz Klich) ## 2.6.1 / 2016-02-08 * Fix a bug where some plugins crashed when used. (Jean Niklas L'orange) ## 2.6.0 / 2016-02-05 * The templates, repl and Leiningen itself now use Clojure 1.8. * Support for Clojure 1.1.0 and older is now dropped. * Warn if possibly stale native dependencies end up in `:native-path`. (Jean Niklas L'orange) * Speed up restarts after `:dependency` changes. (Jean Niklas L'orange) * `lein release` now supports SNAPSHOT on qualifiers. (Chris Price) * Synchronise `lein-pkg` and `lein` scripts. (Thu Trang Pham) * Decrease timeout for the Clojure compiler agent thread pool. (Ryan Fowler) * Fix a bug where implicit resource directories were created by default. (Jean Niklas L'orange) * Avoid optimizing away stack traces by default. (solicode) * Fix a bug where duplicate profiles were merged when profile merging. (Jean Niklas L'orange) * Improved GPG artifact signing feedback. (Jean Niklas L'orange, Andrea Richiardi) * Add function to support binary files with `lein-new`. (Sergiy Bondaryev) * Show better error message when java is not found on the path. (Pavel Prokopenko, Jürgen Hötzel) * Fix a bug with non-GitHub SCM urls in pom files. (Ralf Schmitt) * Don't send aot warning if `:aot` contains regex matching the main namespace. (Emlyn Corrin) ## 2.5.3 / 2015-09-21 * Add CHANGELOG.md to default lein templates. (Daniel Compton) * `lein vcs tag` now supports the `--no-sign` flag. (Daniel Compton) * Fix a bug where javac errors were not printed to terminal. (Brandon Shimanek) * Fix a bug where environment variables were not propagated down to GPG. (Brandon Shimanek) * `lein retest` now saves information on which tests that fail. (Shalaka Patil) * `lein release` now honors exit codes from `git` and throws if non-0 occurs. (Tim Visher) ## 2.5.2 / 2015-08-09 * Allow repl dependencies to be specified in default user profiles. (Jean Niklas L'orange) * Fix a bug where transitive dependencies on tools.nrepl failed. (Jean Niklas L'orange) * Fix a bug preventing custom certificates to work. (Jean Niklas L'orange) * Add support for reader conditional files. (Stephen Nelson) * Add `--template-version` flag to `lein new`. (Ohta Shogo) * Bail immediately if snapshot dependencies are discovered during uberjaring. (Justin Smith) * Use powershell by default in `lein.bat`. (Frederick Giasson, Florian Anderiasch) * Fix bug where manifest files could contain duplicate entries. (Michael Blume) * Allow template designers to use a custom rendering function. (Dmitri Sotnikov) * Fix a bug where `:uberjar-name` wasn't used when inside the `:uberjar` profile. (Kyle Harrington) ## 2.5.1 / 2015-01-09 * No longer skip certificate checking when upgrading on Windows. (Phil Hagelberg) * Fix password prompt for Cygwin users. (Carsten Behring) * Fix a bug where `lein pom` did not add the project's SCM URL to pom.xml. (Fredrick Giasson) * `lein clean` now cleans up all profile targets. (Jeb Beich, Jim Crossley) * The order included profiles are merged in is now retained. (Jim Crossley) * Fix a bug preventing `update-in` to use functions not yet required. (Phil Hagelberg) * Allow multiple `:repl` profiles. (Hugo Duncan) * Fix an infinite recursion bug with aliases and `with-profile`. (Hugo Duncan) * Add flexibility in jar manifest declarations. (Fabio Tudone) * Fix a bug preventing extra profiles from being included in jars. (Hugo Duncan) * Fix a bug in self-install on Windows. (Sindunata Sudarmaji) ## 2.5.0 / 2014-09-14 * Allow certain profiles to be `^:leaky` and affect downstream. (Hugo Duncan) * Allow profiles to be loaded out of plugins. (Phil Hagelberg, Hugo Duncan) * Make `leiningen.core.project/read` init the project and merge default profiles. (Phil Hagelberg) * Move auto-clean to jar task for consistency. (Phil Hagelberg) * Make compilation messages honor `$LEIN_SILENT` (Jean Niklas L'orange) * Fix a bug around EOF in the repl. (Colin Jones) * Add `:implicits` subtask to `deps` task. (Phil Hagelberg) * Update zsh completion rules. (Joshua Davey) * Fix a stack overflow with :pedantic. (Nelson Morris) * Fix a bug where repls outside of a project were broken. (Phil Hagelberg) ## 2.4.3 / 2014-08-05 * Allow implicit hooks/middleware to be disabled. (Phil Hagelberg) * Print compilation errors as they occur. (Paul Legato) * Switch Central repository to using HTTPS. (Manfred Moser) * Add `LEIN_NO_USER_PROFILES` to avoid loading user profile. (Hugo Duncan) * Fix deploy task to work with signature files. (Phil Hagelberg) * Allow vcs tags to be created with a prefix. (Yannick Scherer) * Default to warning when version ranges are present. (Phil Hagelberg) * Let templates be loaded from `:plugin-repositories`. (Jason Felice) ## 2.4.2 / 2014-06-15 * Fix a bug preventing out-of-project runs. (Phil Hagelberg) * Only load Clojars SSL cert on-demand to improve boot time. (Phil Hagelberg) ## 2.4.1 / 2014-06-15 * Don't commit untracked files in `lein vcs commit`. (Phil Hagelberg) * Fix a bug where `:mirrors` could not be configured. (Phil Hagelberg) * Expose `pom.properties` for access to version number during development. (Phil Hagelberg) * Fix a bug preventing the release task from loading. (Phil Hagelberg) ## 2.4.0 / 2014-06-09 * Allow aliases to splice in values from the project map. (Phil Hagelberg) * Allow plugins to override built-in tasks. (Phil Hagelberg) * Add `release` task for automating common release steps. (Wayne Warren, Chris Truter, Phil Hagelberg) * Add `change` task for programmatc `project.clj` manipulation. (Chris Truter, Max Barnash) * Abort when `defproject` contains duplicate keys. (Peter Garbers) * Add `vcs` task to automate version control. (Phil Hagelberg, Wayne Warren) * Automatically `clean` before `deploy` to avoid AOT in libraries. (Phil Hagelberg) * Emit warnings to stderr. (Andy Chambers) * Use `clojure.main` for uberjars that don't declare their own `:main`. (Phil Hagelberg) * Allow templates to load from `:plugin-repositories`. (Phil Hagelberg) * Fix a race condition on printing during dependency resolution. (Phil Hagelberg) * Allow `new` templates to operate on existing directories with `--force` option. (Matthew Blair) * Fix `search` task to allow queries on multiple fields. (Colin Jones) * Fix a bug where errors in `run` task were mis-reported. (Gary Fredericks) * Report download progress of search indices. (Matthew Blair) * Protection from harmful `:clean-targets` settings. (Craig McDaniel) * Faster loading of help text. (David Grayson, Ryan Mulligan) * Add `LEIN_SILENT` option to suppress `*info*` output. (Phil Hagelberg) ## 2.3.4 / 2013-11-18 * Suggest `:exclusions` to possibly confusing `:pedantic?` dependencies. (Nelson Morris, Phil Hagelberg) * Optionally look for snapshot templates in `new` task. (Travis Vachon) * Allow task chains to be declared without commas in project.clj. (Jean Niklas L'orange) * Support extra configurability in `:pom-plugins`. (Dominik Dziedzic) * Fix a bug where implicit :aot warning triggered incorrectly. (Jean Niklas L'orange) * Fix a bug where `lein repl connect` ignored port argument. (Toby Crawley) ## 2.3.3 / 2013-10-05 * Add support for `:uberjar-merge-with`. (Marshall Bockrath-Vandegrift) * Better error message for `-m` arg in `run` task. (Aleksandar Simic) * Support stdin when using `:eval-in :nrepl`. (Phil Hagelberg) * Add directory entries to jar files. (Vadim Platonov) * Fix a bug where `-main` was hard-coded to initial directory. (Phil Hagelberg) ## 2.3.2 / 2013-08-19 * Write `.nrepl-port` file for better tool interoperability. (Phil Hagelberg) * Support targeted upgrades in `lein.bat`. (Shantanu Kumar) * Warn when projects rely on implicit AOT of `:main`. (Phil Hagelberg) * Fix a bug where implicit AOT of `:main` was disabled. (Phil Hagelberg) * Disable profile isolation by default. Will be back in 3.x. (Phil Hagelberg) ## 2.3.1 / 2013-08-13 * Fix self-install bug. (Sam Aaron, Steven Harms) * Fix bug with AOT classes not being included in jars. (Phil Hagelberg) * Support disabling test task's monkeypatch of `clojure.test`. (Phil Hagelberg) * Allow project map to be readable. (Phil Hagelberg) ## 2.3.0 / 2013-08-08 * Add `:eval-in :pprint` for debugging. (Phil Hagelberg) * Support cleaning extra dirs with `:clean-targets`. (Yoshinori Kohyama) * Test-selectors skip fixtures too, not just running tests. (Gary Fredericks) * Place licenses and readmes into jars. (Phil Hagelberg) * Include LICENSE as separate file in templates. (Wolodja Wentland) * Allow aborting on ambiguous version resolution with `:pedantic`. (Nelson Morris, Phil Hagelberg) * Scope `:compile-path` and `:native-path` under profile-specific target dir. (Phil Hagelberg) * Fix bug where uberjar filename would include provided profile. (Phil Hagelberg) * Deprecate explicit `self-install` command. (Phil Hagelberg) * Fix bugs around long lines in jar manifests. (Leon Barrett) * Support nested checkout dependencies. (Phil Hagelberg) * Fix bugs around `:filespecs`. (Jean Niklas L'orange) ## 2.2.0 / 2013-05-28 * Support setting custom welcome message when repl connects. (Colin Jones) * Fix a bug where old template versions were always fetched. (Nelson Morris) * Support `:java-agents` for tooling and instrumenting. (Phil Hagelberg) * Allow checkout dependencies to operate recursively. (Phil Hagelberg) * Introduce `:uberjar` profile. (Phil Hagelberg) * Isolate target paths by profiles. (Phil Hagelberg) * Support deploying ad-hoc files. (Phil Hagelberg) * Set `*command-line-args*` in run task. (Anthony Grimes) * Allow templates to specify executable files. (Joe Littlejohn) * Remove clojuredocs repl support to reduce dependency conflicts. (Phil Hagelberg) ## 2.1.3 / 2013-04-12 * Fix fast trampoline to work without user profiles. (Malcolm Sparks) * Fix a bug where duplicate files in jars would blow up. (Phil Hagelberg) * Fix a bug where cyclical dependencies could cause a crash. (Nelson Morris) * Allow aliases to have docstrings. (Jean Niklas L'orange) * Read credentials from GPG for mirrors. (bdollard) * Fix bugs in `update-in` around profiles and more. (Marko Topolnik) ## 2.1.2 / 2013-02-28 * Add new way to specify no-proxy hosts. (Joe Littlejohn) * Allow TieredCompilation to be disabled for old JVMs. (Phil Hagelberg) * Fix a bug merging keywords in profiles. (Jean Niklas L'orange) * Fix a bug where tests wouldn't run under with-profiles. (Phil Hagelberg) * Support for calling set! on arbitrary vars on startup. (Gary Verhaegen) * Allow update-in to work on top-level keys. (Marko Topolnik) * Fix a bug breaking certain templates. (Colin Jones) * Fix a bug where trampolined repl would hang. (Marko Topolnik) ## 2.1.1 / 2013-03-21 * Add `:test-paths` to directories shared by checkout deps. (Phil Hagelberg) * Allow `run` task to function outside projects. (Phil Hagelberg) * Fix a bug preventing `with-profiles` working outside projects. (Colin Jones) * Fix a bug in trampolined `repl`. (Colin Jones) * Fix a bug in `update-in` task causing stack overflow. (David Powell) * Fix a bug in `lein upgrade`. (Phil Hagelberg) ## 2.1.0 / 2013-03-19 * Compile task accepts regexes as command-line args. (Joshua P. Tilles) * Allow key to be specified to use when signing artifacts. (Tim McCormack) * Added GPG introductory guide. (Toby Crawley) * Many bug fixes in batch file launcher. (David Powell) * Self install via lein.bat no longer requires curl/wget. (slahn) * Allow stdin of project processes to be closed. (Jean Niklas L'orange) * Better behaviour when GPG or keys are missing. (Toby Crawley) * Support customizing key-managers for SSL. (Stephen Nelson) * Add update-in task for arbitrary project map changes. (Phil Hagelberg) * Warn when version ranges are detected. (Nelson Morris) * Add support for msys on Windows machines. (megri) * Allow use of :mirrors when building jars/uberjars. (Tim McCormack) * Dependencies may include native components more flexibly. (Marc Liberatore) * Implement system-level profiles. (Phil Hagelberg) * Accept repo credentials on the CLI for deploy. (Max Prokopiev) * Fix a bug breaking recursive aliases. (Hugo Duncan) * Add support for preventing deployment of branches. (Anthony Grimes) * Improve boot time by limiting tiered compilation in dev. (Phil Hagelberg) * Allow building jars with classifiers. (Hugo Duncan) * Allow :init-ns to be honored by other nrepl clients. (Marko Topolnik) * Add experimental support for :eval-in :nrepl. (Phil Hagelberg) * Don't follow symlinks in clean task. (Jean Niklas L'orange) * Add support for ~/.lein/profiles.d. (Jean Niklas L'orange) * Allow ctrl-c to interrupt repl input (Colin Jones) * Allow `lein test` to take files as arguments (Gabriel Horner) ## 2.0.0 / 2013-01-19 * Allow implicit repl profiles to be overridden. * Accept `:main` as an alias for `-m` in `run` task. * Reader fixes for `repl`. (Colin Jones, Chas Emerick) * Fix bug around stdin for subprocesses that have stopped. (Jean Niklas L'orange) * Warn when `:user` profile is found in `project.clj`. (Michael Grubb) * Treat `:user` profile as project map outside of project. (Jean Niklas L'orange) ## 2.0.0-RC2 / 2013-01-12 * Fix bug where newnew wouldn't be loaded from outside a project. * Fix Windows bug in project generation. * Fix `lein upgrade` bug. ## 2.0.0-RC1 / 2013-01-10 * Fix some reader bugs in repl task. (Colin Jones) * Fix a bug where Leiningen's deps could affect javac. (Jean Niklas L'orange) * Test selectors may allow entire namespaces to be skipped. (Anthony Grimes) * Allow project's git repo to be different than project root. (David Greenberg) * Don't AOT the `:main` namespace outside of jar/uberjar task. * Allow hooks from profiles to apply with limited scope. (Hugo Duncan) * Fix a bug where profile-specific paths were ignored in trampoline. * Support reading from stdin inside project process. * Add `:only` test selector. (Anthony Grimes) * Support partial application for test selectors. (Anthony Grimes) * Un-deprecate `:auth` profile for full-disk-encryption users. * Add documentation for mixed-source projects. (Michael Klishin) * Make later profiles take precedence in with-profile task. (Justin Balthrop) * Improve help for subtasks. (Tobias Crawley) * Allow vectors to specify multiple credential sources. (Chas Emerick) * Look up credentials in environment using namespaced keywords. (Chas Emerick) * Support overriding repl profile from project.clj or profiles.clj. * Allow test selectors to operate on namespace. (Jim Crossley) * Honor environment variables in project.clj. (Justin Balthrop) * Allow searching over fields other than artifact id. (Michael Klishin) * Honor per-project REPL history. (Michael Klishin, Colin Jones) * Reduce output during dependency resolution. (Nelson Morris) * Fix search task outside project. (Bruce Adams) ## 2.0.0-preview10 / 2012-08-25 * Fix a bug where repositories wouldn't be checked running outside a project. * Make repl listen on 127.0.0.1 instead of localhost to address IPv6 issues. ## 2.0.0-preview9 / 2012-08-24 * Use provided profile by default everywhere except uberjar. (Marshall Vandegrift) * Unify format for auto-loading middleware and hooks. (Justin Balthrop) * Allow more declarative :nrepl-middleware settings. (Chas Emerick) * Fix `:eval-in :classloader` for native dependencies. (Justin Balthrop) * Support project and user leinrc file for shell-level customization. (Justin Balthrop) * Cache trampoline commands for fast boot. Set `$LEIN_FAST_TRAMPOLINE` to enable. * Support setting HTTPS proxies. * Improved resilience when self-install is interrupted. (Bruce Adams) * Fix a bug where profile dependencies weren't honored in trampoline task. ## 2.0.0-preview8 / 2012-08-16 * Place SCM revision in pom.properties in jar files. * Allow middleware and hooks to be inferred from plugins. (Justin Balthrop) * Offer similar suggestions when no task is found for input. (Joe Gallo) * Support `TERM=dumb` in repl task. (Colin Jones) * Fix reader mismatches between repl client and server. (Colin Jones) * Use new search index format, support incremental updates. (Christoph Seibert) * Accept nREPL handlers and middleware from project config. * Support emitting arbitrary elements in pom.xml. (Esa Laine) * Fix a bug where repl task was binding to 0.0.0.0. * Honor `$http_no_proxy` host settings. (Jon Pither) * Profiles can be specified as compositions of other profiles. (Justin Balthrop) * Allow for `:prep-tasks` with arguments. (Anthony Marcar) * Check for "help" after task name. (Bruce Adams) * Read dependency transport wagons from plugins. * Allow successive eval-in-project calls with trampoline. * Bring back selective post-compile cleaning. (Arlen Cuss) * Fix memory leak in repl task. ## 2.0.0-preview7 / 2012-06-27 * Fix a bug where failed javac wouldn't abort. (Michael Klishin) * Check task aliases everywhere tasks are invoked. * Sign jars and poms of releases upon deploy by default. * Don't decrypt `credentials.clj.gpg` for every request. * Support setting `:mirrors` in project.clj. (Chas Emerick, Nelson Morris) * Allow aliases shadowing task names to invoke shadowed tasks. * Emit `doc/intro.md` in new project templates. * Allow `:scm` to be set in project.clj for pom inclusion. (Florian Anderiasch) * Fix a bug where dependency `:classifier` and `:extension` would be ignored. * Speed up subprocess launches when `:bootclasspath` is set. * Set user agent for HTTP requests. (Bruce Adams) * Verify signatures of dependencies with `lein deps :verify`. * Move task chaining to `do` task in order to allow for higher-order use. ## 2.0.0-preview6 / 2012-06-01 * Allow lookup of `:repositories` credentials from environment variables. * Perform more SSL certificate validity checks. * Fix a bug where repl dependency was conflicting. * Add certificate for Clojars to default project settings. * Allow custom SSL `:certificates` to be specified for repositories. ## 2.0.0-preview5 / 2012-05-31 * Fix a repl bug where namespaced keywords weren't read right. (Colin Jones) * Prompt for credentials upon deploy when none are configured. * Support encrypted deploy credentials using GPG. * Warn about missing metadata when deploying. * Default to refusing downloaded jars when checksums don't match. * Apply middleware before calculating profiles so they work in with-profile. * Allow reply dependency to be upgraded independently of Leiningen. * Don't write "stale" directory when running outside a project. * Proxy settings are passed on to project subprocesses. (Craig McDaniel) * Revamp tutorial, spin off profiles guide and faq. * Fix bug that would cause repl task to hang. (Colin Jones) ## 2.0.0-preview4 / 2012-05-11 * Checkout dependencies are not applied with production profile. * Move pom.xml back to the project root. * Add -U alias for forcing updates of snapshots. * Support setting :update and :checksum profiles at top level of project. * Blink matching parens in repl. (Colin Jones) * Fix a bug where repl would interfere with project agents. (Chas Emerick) * Show repl output that is emitted after return value. (Colin Jones) * Make it easier for plugins to undo profile merging. (David Santiago) * Add -o alias for activating offline profile. * Ignore $CLASSPATH environment variable. * Fix bug where repl task couldn't be trampolined. (Colin Jones) * Allow jar manifest entries to be dynamically calculated. * Support map-style :javac-opts like Leiningen 1.x used. (Michael Klishin) * Allow group-id to be specified when creating new projects. (Michael Klishin) * Fix a bug where :dev dependencies would be exposed in pom. * Use Clojure 1.4.0 internally; plugins have access to new Clojure features. ## 2.0.0-preview3 / 2012-04-12 * Add HTTP nREPL support for repl task via :connect option. (Chas Emerick, Phil Hagelberg) * Improve repl startup time, output consistency, Windows support. (Lee Hinman, Colin Jones) * Stop using numeric exit codes for task failures. * Dynamically resolve unknown templates in new task. * Automatically activate offline profile when needed. * Honor $http_proxy environment variable. (Juergen Hoetzel) * Allow arbitrary :filespecs to be included in jars. * Let custom :prep-tasks be specified in project.clj. * Include :java-source-paths and dev/test deps in pom. (Nelson Morris) * Add offline profile. * Prevent project JVMs from outlasting Leiningen's process. (Colin Jones) * Update lein.bat to work with version 2. (Andrew Kondratovich) * Show a dependency tree in deps task. (Chas Emerick, Nelson Morris) * Support connecting to nrepl server in repl task. (Chas Emerick, Colin Jones) * Pretty-print pom.xml. (Nelson Morris) * Display task aliases in help task. (Michael S. Klishin) * Only compile stale java source files. (Stephen C. Gilardi) * Respect :java-cmd in project.clj. (Michael S. Klishin) * Show progress when downloading search indices. (Justin Kramer) ## 2.0.0-preview2 / 2012-03-08 * Honor :default and :user profiles when running outside a project. * Fix a bug where subtask help wasn't showing. ## 2.0.0-preview1 / 2012-03-07 * Split out leiningen-core into independent library. * Construct classpath out of ~/.m2 instead of copying jars to lib/. * Replace maven-ant-tasks with Pomegranate library. (Chas Emerick, Nelson Morris) * Move build artifacts to target/ directory. * Add experimental support for running project code in-process with :eval-in :classloader. (Justin Balthrop) * Support profiles for alternate project configurations. * Switch to using plural :source-paths, :test-paths, and :resource-paths. * Complete rewrite of repl task. (Colin Jones, Chas Emerick, Anthony Grimes) * Remove special case of implicit org.clojure group-id in :dependencies. * Replace :dev-dependencies with :dev profile. * Support customized :source-paths with :eval-in :leiningen projects. * Rewrite pom task. (Nelson Morris, Alan Malloy) * Allow tasks and projects to add custom :injections into project code. * Support changing :prep-tasks for running tasks other than javac and compile before eval-in-project calls. * Rewrite new task. (Anthony Grimes) * New check task for catching reflection and other issues. (David Santiago) * Check project.clj for :aliases. * Allow partial application of aliases. * Drop :extra-classpath-dirs option. * Load :plugins without trampolining the process. * Remove plugin task in favour of :user profile. * Allow :repository-auth to be specified using a regular expression. * Support arbitrary project map transformation functions via :middleware. * Support changing :local-repo path in project.clj. ## 1.7.1 / 2012-03-27 * Fix a bug where the repl task left JVM processes running. * Make upgrade task accept arbitrary versions. * Fix a bug where javac classes would get removed before AOT compilation. * Allow :aot to contain both symbols and regexes. (Dan Lidral-Porter) * Fix bug where clean task would be incredibly slow. * Apply :jvm-opts with :eval-in-leiningen. * Prevent misbehaving plugins from pulling in conflicting Clojure versions. ## 1.7.0 / 2012-02-06 * Allow any task to perform trampolining. * Fix a bug where JVM_OPTS with spaces would cause failures. * Keep pom dependencies off the classpath. * Block plugins from erroneously including their own Clojure version. * Allow poms to set parent element. (Nelson Morris) * Support emitting Maven extensions in pom. (Max Penet) * Allow faster booting on 64-bit JVMs with tiered compilation. * Fix a bug where shell wrappers had the wrong classpath. (Tavis Rudd) * Exclude all signature files from uberjars. (Tim McCormack) * Allow test selectors to apply to entire namespaces. (Kevin Downey) * Use LEIN_JAVA_CMD to allow different JVM for Leiningen itself. (Tavis Rudd) * Honor :plugins key inside project.clj. * Accept :repl-init namespace as argument to repl task. * Allow :java-source-path to be nested inside :source-path. (Anthony Grimes) * Fix a bug where native deps weren't made available. (Anthony Grimes) ## 1.6.2 / 2011-11-11 * Let run task work with main functions from Java classes. * Fix bug where exceptions would break interactive task. * Default to Clojure 1.3.0 for new projects. * Allow Leiningen home to exist inside project directory. (Heinz N. Gies) * Remove old versions of plugins when upgrading. * Add user-level :deploy-repositories list. (Michał Marczyk) * Fix a bug where class files from proxy objects weren't considered part of the project. (Stephen Compall) * Make deps cause implicit clean to avoid AOT version mismatches. * Include Java source files in jar. (Nathan Marz) * Add separate :deploy-repositories list. (Chas Emerick) * Maintain order in repositories list. (Colin Jones) * Fix a bug where :omit-default-repos wouldn't skip Maven Central. (Chas Emerick) * Make deps extract native dependencies for all architectures, not just current. * Fix page count on search results. * Fix a bug where "lein plugin install" could skip dependencies. * Reimplement eval-in-project to use clojure.java.shell instead of Ant. * Separate LEIN\_JVM\_OPTS from JVM_OPTS. ## 1.6.1.1 / 2011-09-06 * Turn off workaround for Clojure's agent thread pool keeping the JVM alive by default. Use :shutdown-agents in project.clj to enable it. ## 1.6.1 / 2011-07-06 * Allow alternate main namespace to be used during uberjar creation. * Add :checkout-deps-shares to share more directories in checkout dependencies. * Fix a bug where agent thread pool would be shut down in repl task. * Support :project-init in project.clj to allow pprint to be used in :repl-options. * Fix a bug where tests would not run using Clojure 1.3. * Support for .classpath file to include context specific classpath elements. ## 1.6.0 / 2011-06-29 * Enforce project names as readable symbols. * Add trampoline task. * Fix a bug where plugins would be unavailable in MinGW. * Allow functions other than -main to be called using run task. * Support constructing classpath out of ~/.m2 instead of copying to lib/. * Fix a bug where help output could be truncated by plugin issues. * Support native dependencies. * Test selectors no longer require additional hooke dependency. * Add retest task. * Add search task. * Remove deprecated build.clojure.org repositories. * Remove user/\*classpath\* var. * Support :extra-classpath-dirs in project.clj. ## 1.5.2 / 2011-04-13 * Check rlwrap for support of custom quotes before using. * Improve Solaris support. (Donald Clark Jackson) * Fix curl error relating to missing $https_proxy. (Pirmin Fix) ## 1.5.1 / 2011-04-12 * Improve rlwrap quote support. (Ambrose Bonnaire-Sergeant) * Prevent ns load exceptions from halting help. * Fix :repl-init namespace handling. * Make deps for :eval-in-leiningen projects available to lein process. * Pass $https_proxy environment variable to curl. * Fix :eval-in-leiningen when used with init arg. * Pom now includes dev-dependencies as test-scoped. (Thomas Engelschmidt) * Fix handling of arguments with spaces. (Stuart Fehr) * Fix a plugin bug where it would look for dev-dependencies. * Fix :min-lein-version checking. (Colin Jones) * Honor user settings in more places. * Fix running-as-root warning. * Revert back to warning when repository checksums don't match. ## 1.5.0 / 2011-03-22 * New projects now use Clojure 1.2.1. * Honor per-repository :update/:checksum policies. * Allow some repositories to be releases/snapshots-only. * Honor global :exclusions. (Joe Gallo) * Honor :class-file-whitelist to make classes/ deletion more manageable. * Accept :repl-init namespace in project.clj. * Warn when falling back to jline if rlwrap is not found. * Add prepend-task macro for simple hook usage. * Add flexibility to clean task with :extra-files-to-clean and :regex-to-clean. * Fix bug in interactive task that would cause infinite loop. * Add version into shell wrapper template. * Add pcmpl-lein.el for eshell completion. * Skip fetching dependencies when they haven't changed in project.clj if :checksum-deps is set. * Add system property for $PROJECT.version. * Add deploy task. * Reload tests in interactive mode. * Make test! task accept namespace list as argument. (Joe Gallo) * Use current year in readme for project skeleton. (Joe Gallo) ## 1.4.2 / 2010-12-31 * Fix a bug where init to eval-in-project was ignored in interactive task. * Fix a bug in path calculation for native dependencies. (wburke) * Fix a bug where built-in tasks shadowed plugins (javac, run). * Allow a seq of regexes in :clean-non-project-classes for more flexibility. * Fix a bug where the first argument to run would be parsed wrong. (Alex Osborne) * Use JVM\_OPTS environment variable instead of JAVA\_OPTS, though the latter is still supported for backwards-compatibility. ## 1.4.1 / 2010-12-16 * Allow boosting :repl-retry-limit in project.clj for slow-starting projects. * Turn :clean-non-project-classes off by default. * Support :skip-aot metadata on :main in project.clj. * Alias :deps/:dev-deps to :dependencies/:dev-dependencies in project.clj. * Support setting clojure.debug property. * Don't allow stable versions to depend upon snapshots. * Fix exit code for chained tasks. ## 1.4.0 / 2010-12-02 * Support readme, tutorial, news, and copying in help task. * Show short help summaries in help task overview. * Keep project JVM running between task runs in interactive task. * Support :uberjar-exclusions as a seq of regexes in project.clj. * Support :repl-options in project.clj that get passed to clojure.main/repl. * Shell wrappers are installed on Windows. (Matjaz Gregoric) * Windows and Cygwin path fixes. (Matjaz Gregoric) * Solaris compatibility fixes. (Heinz Gies) * Deprecated :jar-dir in favour of :target-dir. * Deprecated unused eval-in-project arguments. (handler, skip-auto-compile) * Deprecated :namespaces and :test-resources-path in project.clj. * Delete non-project .class files after AOT compilation. (Luc Prefontaine) * Merge run task from lein-run plugin. (Siddhartha Reddy) * Improve subtask help output. (Colin Jones) * Support :eval-in-leiningen for easier testing of plugins. * Merge javac task from lein-javac plugin. (Antonio Garrote) * Add init argument to eval-in-project to help with the Gilardi Scenario. See http://technomancy.us/143 for details. * Fix bug involving repl I/O flushing. * Run subset of test suite using test selector predicates. * Specify what file patterns to exclude from jars. (Zehua Liu) * Sort and de-dupe help output. (Sergio Arbeo) * Add plugin task: easily install user-level plugins (Colin Jones, Michael Ivey) ## 1.3.1 / 2010-09-07 * Support regex matching in :aot list. (Alex Ott) * Run self-install automatically if uberjar is missing. * Fix bugs that caused standalone install task to fail. * Allow dependency type to be specified in project.clj. (John Sanda) * Stop jar/uberjar task if compile fails. (Alan Dipert) * Support :min-lein-version in project.clj so if a project uses newer Leiningen features it will warn users of old lein versions. (Isaac Hodes) * Fix a bug where tests would get skipped if their first form was not ns. * Fix a bug where "lein help" would hang if run from a dir with a large src/. * Fix a bug where repl task would hang on unreadable input. (Isaac Hodes) * Allow repl task to work outside project. (Colin Jones) * If curl/wget is found, self-install works on Windows. (Shantanu Kumar) * Fix bug causing standalone install task to fail. * Allow custom shell-wrappers. * Start repls in user ns if no :main is in project.clj. ## 1.3.0 / 2010-08-19 * Add :omit-source option to project.clj for shipping aot-only jars. * Make repl task listen on a socket as well as the command-line. * Write shell wrapper scripts at installation time. See TUTORIAL.md. * Put user-level plugins in ~/.lein/plugins on the classpath. * Load ~/.lein/init.clj on startup. * Execution of per-project initialization script, specified in :repl-init-script option. (Alex Ott) * Switch to /bin/sh instead of bash. (Mike Meyer) * Allow multiple tasks to be chained from the command-line. (Colin Jones) * Add test! task that cleans and does deps before testing. * Add interactive task for entering tasks in a shell-like environment. * Work around argument escaping bug on Windows. (Laurence Hygate) * Require hooks to be specified in project.clj. * Detect download failures in self-install. * Add resources and test-resources paths to pom. (Brian Weber) * Fix bug causing crash if OS name wasn't recognized. * Improve AOT staleness determination heuristic. * Fix bug where uberjar left out dependencies for non-AOT'd projects. (Alex Ott) ## 1.2.0 / 2010-07-18 * Don't enable repl rlwrap when unnecessary. (dumb terms, Emacs, etc.) * Add support for password-protected repositories. * Allow :jar-name and :uberjar-name to be customized. * Allow unquoting in defproject form. * Support classifiers in dependencies. * Clean before running uberjar task. * Implicitly clean lib/ before running deps. * Add support for test-resources directory. * Fix help output that AOT sometimes drops. * Clear out lib/dev on lein clean even if :library-path is customized. * Some tasks suppress useless output. * Snapshot versions now allow self-install. * Allow compile task to take a list of namespaces overriding project.clj. * Handle more types of project metadata. * Add plugin creation guide. * Include arglists in help output. * Make lein script usable from any subdirectory in the project root. * Fix repl task to work with forked subprocess. * Fork subprocess unconditionally for greater compatibility. * Allow $JAVA_CMD to be customized. * Fix a bug causing everything to recompile in tests. Thanks, Stuart! * Fix exit code for test runs. * Automatically compile and fetch deps when needed. * Allow :jvm-opts and :warn-on-reflection to be set in project.clj. * Merge lein-swank plugin into swank-clojure. * Add :aot as an alias in project.clj for :namespaces to AOT-compile. * Add option to omit-default-repositories. * Allow group-id to be omitted when depending on Clojure and Contrib. * Keep dev-dependencies in lib/dev, exclude them from uberjars. * Include version numbers in jar filenames. * Fix repl task to use project subclassloader. * Don't allow "new" task to create *jure names. * Add classpath command. * Implement Checkout Dependencies. See README. * Add option to symlink deps into lib/ instead of copying. * Fixed bug for file timestamps inside jars. * Generated poms should work in Java IDEs. * Improved Cygwin support. * Added TUTORIAL.md file for introductory concepts. ## 1.1.0 / 2010-02-16 * Added "lein upgrade" task * Don't download snapshot releases unless actually needed. * Make subclassloader's classpath available to projects. * Fixed "install" task to place pom in local repository. * Bug fixes to "new" task. * Only AOT-compile namespaces specified in project.clj. * Better error handling. * Add exclusions support for dependencies. * Support dependencies with native code. * Added experimental Windows support. ## 1.0.1 / 2009-12-10 * Added bash completion. * Honor $JAVA_OPTS. * Fix new task. * Add version task. * Use jline for repl task. * Fix pom task for Java 1.5 compatibility. ## 1.0.0 / 2009-12-05 * Source, test, and compilation paths can be set in project.clj. * Project code runs in an isolated classloader; can now compile/test projects that require a different version of Clojure from Leiningen. (Does not support 1.0's test-is yet.) * Install task no longer requires maven to be installed. * Only compile namespaces whose .class files are older than .clj files. * Add "new" task for generating blank projects. * Set tag when generating pom.xml. * Include pom.xml, pom.properties, and more detailed manifest in jars. * Summarize pass/fail counts from test runs across all namespaces. * Accept a list of namespaces for test task rather than testing all. * Create $PROJECT-standalone.jar file from uberjar to distinguish from regular jar files. * Plugins have more flexibility to set the classpath and other arguments for running project code. * Add resources/ directory to classpath and generated jars. * Start Leiningen faster by using -Xbootclasspath argument. ## 0.5.0 / 2009-11-17 * Initial release! leiningen-2.9.1/README.md000066400000000000000000000134211343535564500147700ustar00rootroot00000000000000# Leiningen [![CircleCI](https://circleci.com/gh/technomancy/leiningen.svg?style=svg)](https://circleci.com/gh/technomancy/leiningen) Leiningen logo > "Leiningen!" he shouted. "You're insane! They're not creatures you can > fight—they're an elemental—an 'act of God!' Ten miles long, two > miles wide—ants, nothing but ants! And every single one of them a > fiend from hell..." > - from [Leiningen Versus the Ants](http://www.classicshorts.com/stories/lvta.html) by Carl Stephenson Leiningen is for automating Clojure projects without setting your hair on fire. ## Installation If your preferred [package manager](https://github.com/technomancy/leiningen/wiki/Packaging) offers a recent version of Leiningen, try that first as long as it has version 2.x. Leiningen installs itself on the first run of the `lein` shell script; there is no separate install script. Follow these instructions to install Leiningen manually: 1. Make sure you have Java installed; OpenJDK version 8 is recommended at this time. 2. [Download the `lein` script from the `stable` branch](https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein) of this project. 3. Place it on your `$PATH`. (`~/bin` is a good choice if it is on your path.) 4. Set it to be executable. (`chmod +x ~/bin/lein`) 5. Run it. Windows users can use the above script in the Linux subsystem or try [the batch file](https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.bat) or [Powershell version](https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.ps1) instead. ## Basic Usage The [tutorial](https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md) has a detailed walk-through of the steps involved in creating a new project, but here are the commonly-used tasks: $ lein new [TEMPLATE] NAME # generate a new project skeleton $ lein test [TESTS] # run the tests in the TESTS namespaces, or all tests $ lein repl # launch an interactive REPL session $ lein run -m my.namespace # run the -main function of a namespace $ lein uberjar # package the project and dependencies as standalone jar $ lein deploy clojars # publish the project to Clojars as a library Use `lein help` to see a complete list. `lein help $TASK` shows the usage for a specific task. You can also chain tasks together in a single command by using the `do` task with comma-separated tasks: $ lein do clean, test foo.test-core, jar Most tasks need to be run from somewhere inside a project directory to work, but some (`new`, `help`, `search`, `version`, and `repl`) may run from anywhere. ## Configuration The `project.clj` file in the project root should look like this: ```clj (defproject myproject "0.5.0-SNAPSHOT" :description "A project for doing things." :license "Eclipse Public License 1.0" :url "http://github.com/technomancy/myproject" :dependencies [[org.clojure/clojure "1.8.0"]] :plugins [[lein-tar "3.2.0"]]) ``` The `lein new` task generates a project skeleton with an appropriate starting point from which you can work. See the [sample.project.clj](https://github.com/technomancy/leiningen/blob/stable/sample.project.clj) file (also available via `lein help sample`) for a detailed listing of configuration options. The `project.clj` file can be customized further with the use of [profiles](https://github.com/technomancy/leiningen/blob/stable/doc/PROFILES.md). ## Documentation Leiningen documentation is organized as a number of guides: ### Usage * [Tutorial](https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md) (start here if you are new) * [FAQ](https://github.com/technomancy/leiningen/blob/stable/doc/FAQ.md) * [Profiles](https://github.com/technomancy/leiningen/blob/stable/doc/PROFILES.md) * [Deployment & Distribution of Libraries](https://github.com/technomancy/leiningen/blob/stable/doc/DEPLOY.md) * [Sample project.clj](https://github.com/technomancy/leiningen/blob/stable/sample.project.clj) * [Polyglot (e.g. Clojure/Java) projects](https://github.com/technomancy/leiningen/blob/stable/doc/MIXED_PROJECTS.md) ### Development * [Writing Plugins](https://github.com/technomancy/leiningen/blob/stable/doc/PLUGINS.md) * [Writing Templates](https://github.com/technomancy/leiningen/blob/stable/doc/TEMPLATES.md) * [Contributing](https://github.com/technomancy/leiningen/blob/stable/CONTRIBUTING.md) * [Building Leiningen](https://github.com/technomancy/leiningen/blob/stable/CONTRIBUTING.md#bootstrapping) ## Plugins Leiningen supports plugins which may introduce new tasks. See [the plugins wiki page](https://github.com/technomancy/leiningen/wiki/Plugins) for a full list. If a plugin is needed for successful test or build runs, (such as `lein-tar`) then it should be added to `:plugins` in project.clj, but if it's for your own convenience (such as `lein-pprint`) then it should be added to the `:plugins` list in the `:user` profile in `~/.lein/profiles.clj`. See the [profiles guide](https://github.com/technomancy/leiningen/blob/stable/doc/PROFILES.md) for details on how to add to your `:user` profile. The [plugin guide](https://github.com/technomancy/leiningen/blob/stable/doc/PLUGINS.md) explains how to write plugins. ## License Source Copyright © 2009-2018 Phil Hagelberg, Alex Osborne, Dan Larkin, and [contributors](https://github.com/technomancy/leiningen/contributors). Distributed under the Eclipse Public License, the same as Clojure uses. See the file COPYING. Thanks to Stuart Halloway for Lancet and Tim Dysinger for convincing me that good builds are important. Images Copyright © 2010 Phil Hagelberg. Distributed under the Creative Commons Attribution + ShareAlike License. [Full-size version](https://leiningen.org/img/leiningen-full.jpg) available. leiningen-2.9.1/TUTORIAL.md000066400000000000000000000001401343535564500152700ustar00rootroot00000000000000The [tutorial has moved](https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md)! leiningen-2.9.1/bash_completion.bash000066400000000000000000000030471343535564500175210ustar00rootroot00000000000000_lein_completion() { local cur prev tasks COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" tasks="change check classpath clean compile deploy deps do help install jar javac new plugin pom release repl retest run search show-profiles test trampoline uberjar update-in upgrade vcs version with-profile" case "${prev}" in change | check | classpath | clean | deploy | deps | do | install | jar | javac | new | plugin | pom | release | repl | show-profiles | uberjar | update-in | vcs | version) COMPREPLY=() ;; help) # Show tasks again, but only once; don't infinitely recurse local prev2="${COMP_WORDS[COMP_CWORD-2]}" if [ "$prev2" == "help" ]; then COMPREPLY=() else COMPREPLY=( $(compgen -W "${tasks}" -- ${cur}) ) fi ;; test | retest ) # list project's test namespaces: local namespaces=$(find test/ -type f -name "*.clj" -exec sed -n 's/^(ns[ ]*//p' '{}' '+') COMPREPLY=( $(compgen -W "${namespaces}" -- ${cur}) ) ;; run | compile) # list project's src namespaces: local namespaces=$(find src/ -type f -name "*.clj" -exec sed -n 's/^(ns[ ]*//p' '{}' '+') COMPREPLY=( $(compgen -W "${namespaces}" -- ${cur}) ) ;; lein) COMPREPLY=( $(compgen -W "${tasks}" -- ${cur}) ) ;; esac return 0 } complete -F _lein_completion lein leiningen-2.9.1/bin/000077500000000000000000000000001343535564500142605ustar00rootroot00000000000000leiningen-2.9.1/bin/issues.clj000066400000000000000000000022461343535564500162710ustar00rootroot00000000000000;; This is just a one-off tool to classify/summarize issues programmatically. (try (require 'tentacles.issues) (catch java.io.FileNotFoundException _ (cemerick.pomegranate/add-dependencies :repositories [["clojars" {:url "https://clojars.org/repo/"}]] :coordinates '[[tentacles "0.2.7"]]) (require 'tentacles.issues))) (defn labeled? [label issue] (some #(= (:name %) label) (:labels issue))) (def low-priority? #{1566 1544 1319 1363 1155}) (def order ["2.4.3" "other" "Enhancement" "docs" "low" "3.0.0"]) (defn categorize [i] (cond (labeled? "Windows" i) nil (:title (:milestone i)) (:title (:milestone i)) (labeled? "Enhancement" i) "Enhancement" (labeled? "docs" i) "docs" (low-priority? (:number i)) "low" :else "other")) (defn report [] (doseq [[category issues] (->> (tentacles.issues/issues "technomancy" "leiningen") (group-by categorize) (sort-by #(.indexOf order (key %)))) :when category] (println "\n#" category) (doseq [i issues] (println (:number i) "-" (:title i))))) leiningen-2.9.1/bin/lein000077500000000000000000000303711343535564500151410ustar00rootroot00000000000000#!/usr/bin/env bash # Ensure this file is executable via `chmod a+x lein`, then place it # somewhere on your $PATH, like ~/bin. The rest of Leiningen will be # installed upon first run into the ~/.lein/self-installs directory. function msg { echo "$@" 1>&2 } export LEIN_VERSION="2.9.1" case $LEIN_VERSION in *SNAPSHOT) SNAPSHOT="YES" ;; *) SNAPSHOT="NO" ;; esac if [[ "$CLASSPATH" != "" ]]; then cat <<-'EOS' 1>&2 WARNING: You have $CLASSPATH set, probably by accident. It is strongly recommended to unset this before proceeding. EOS fi if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then delimiter=";" else delimiter=":" fi if [[ "$OSTYPE" == "cygwin" ]]; then cygwin=true else cygwin=false fi function command_not_found { msg "Leiningen couldn't find $1 in your \$PATH ($PATH), which is required." exit 1 } function make_native_path { # ensure we have native paths if $cygwin && [[ "$1" == /* ]]; then echo -n "$(cygpath -wp "$1")" elif [[ "$OSTYPE" == "msys" && "$1" == /?/* ]]; then echo -n "$(sh -c "(cd $1 2&2 Failed to download $1 (exit code $2) It's possible your HTTP client's certificate store does not have the correct certificate authority needed. This is often caused by an out-of-date version of libssl. It's also possible that you're behind a firewall and haven't set HTTP_PROXY and HTTPS_PROXY. EOS } function self_install { if [ -r "$LEIN_JAR" ]; then cat <<-EOS 1>&2 The self-install jar already exists at $LEIN_JAR. If you wish to re-download, delete it and rerun "$0 self-install". EOS exit 1 fi msg "Downloading Leiningen to $LEIN_JAR now..." mkdir -p "$(dirname "$LEIN_JAR")" LEIN_URL="https://github.com/technomancy/leiningen/releases/download/$LEIN_VERSION/leiningen-$LEIN_VERSION-standalone.zip" $HTTP_CLIENT "$LEIN_JAR.pending" "$LEIN_URL" local exit_code=$? if [ $exit_code == 0 ]; then # TODO: checksum mv -f "$LEIN_JAR.pending" "$LEIN_JAR" else rm "$LEIN_JAR.pending" 2> /dev/null download_failed_message "$LEIN_URL" "$exit_code" exit 1 fi } NOT_FOUND=1 ORIGINAL_PWD="$PWD" while [ ! -r "$PWD/project.clj" ] && [ "$PWD" != "/" ] && [ $NOT_FOUND -ne 0 ] do cd .. if [ "$(dirname "$PWD")" = "/" ]; then NOT_FOUND=0 cd "$ORIGINAL_PWD" fi done export LEIN_HOME="${LEIN_HOME:-"$HOME/.lein"}" for f in "/etc/leinrc" "$LEIN_HOME/leinrc" ".leinrc"; do if [ -e "$f" ]; then source "$f" fi done if $cygwin; then export LEIN_HOME=$(cygpath -w "$LEIN_HOME") fi LEIN_JAR="$LEIN_HOME/self-installs/leiningen-$LEIN_VERSION-standalone.jar" # normalize $0 on certain BSDs if [ "$(dirname "$0")" = "." ]; then SCRIPT="$(which "$(basename "$0")")" if [ -z "$SCRIPT" ]; then SCRIPT="$0" fi else SCRIPT="$0" fi # resolve symlinks to the script itself portably while [ -h "$SCRIPT" ] ; do ls=$(ls -ld "$SCRIPT") link=$(expr "$ls" : '.*-> \(.*\)$') if expr "$link" : '/.*' > /dev/null; then SCRIPT="$link" else SCRIPT="$(dirname "$SCRIPT"$)/$link" fi done BIN_DIR="$(dirname "$SCRIPT")" export LEIN_JVM_OPTS="${LEIN_JVM_OPTS-"-Xverify:none -XX:+TieredCompilation -XX:TieredStopAtLevel=1"}" # This needs to be defined before we call HTTP_CLIENT below if [ "$HTTP_CLIENT" = "" ]; then if type -p curl >/dev/null 2>&1; then if [ "$https_proxy" != "" ]; then CURL_PROXY="-x $https_proxy" fi HTTP_CLIENT="curl $CURL_PROXY -f -L -o" else HTTP_CLIENT="wget -O" fi fi # When :eval-in :classloader we need more memory grep -E -q '^\s*:eval-in\s+:classloader\s*$' project.clj 2> /dev/null && \ export LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Xms64m -Xmx512m" if [ -r "$BIN_DIR/../src/leiningen/version.clj" ]; then # Running from source checkout LEIN_DIR="$(cd $(dirname "$BIN_DIR");pwd -P)" # Need to use lein release to bootstrap the leiningen-core library (for aether) if [ ! -r "$LEIN_DIR/leiningen-core/.lein-bootstrap" ]; then cat <<-'EOS' 1>&2 Leiningen is missing its dependencies. Please run "lein bootstrap" in the leiningen-core/ directory with a stable release of Leiningen. See CONTRIBUTING.md for details. EOS exit 1 fi # If project.clj for lein or leiningen-core changes, we must recalculate LAST_PROJECT_CHECKSUM=$(cat "$LEIN_DIR/.lein-project-checksum" 2> /dev/null) PROJECT_CHECKSUM=$(sum "$LEIN_DIR/project.clj" "$LEIN_DIR/leiningen-core/project.clj") if [ "$PROJECT_CHECKSUM" != "$LAST_PROJECT_CHECKSUM" ]; then if [ -r "$LEIN_DIR/.lein-classpath" ]; then rm "$LEIN_DIR/.lein-classpath" fi fi # Use bin/lein to calculate its own classpath. if [ ! -r "$LEIN_DIR/.lein-classpath" ] && [ "$1" != "classpath" ]; then msg "Recalculating Leiningen's classpath." cd "$LEIN_DIR" LEIN_NO_USER_PROFILES=1 "$LEIN_DIR/bin/lein" classpath .lein-classpath sum "$LEIN_DIR/project.clj" "$LEIN_DIR/leiningen-core/project.clj" > \ .lein-project-checksum cd - fi mkdir -p "$LEIN_DIR/target/classes" export LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Dclojure.compile.path=$LEIN_DIR/target/classes" add_path CLASSPATH "$LEIN_DIR/leiningen-core/src/" "$LEIN_DIR/leiningen-core/resources/" \ "$LEIN_DIR/test:$LEIN_DIR/target/classes" "$LEIN_DIR/src" ":$LEIN_DIR/resources" if [ -r "$LEIN_DIR/.lein-classpath" ]; then add_path CLASSPATH "$(cat "$LEIN_DIR/.lein-classpath" 2> /dev/null)" else add_path CLASSPATH "$(cat "$LEIN_DIR/leiningen-core/.lein-bootstrap" 2> /dev/null)" fi else # Not running from a checkout add_path CLASSPATH "$LEIN_JAR" if [ "$LEIN_USE_BOOTCLASSPATH" != "no" ]; then LEIN_JVM_OPTS="-Xbootclasspath/a:$LEIN_JAR $LEIN_JVM_OPTS" fi if [ ! -r "$LEIN_JAR" -a "$1" != "self-install" ]; then self_install fi fi if [ ! -x "$JAVA_CMD" ] && ! type -f java >/dev/null then msg "Leiningen couldn't find 'java' executable, which is required." msg "Please either set JAVA_CMD or put java (>=1.6) in your \$PATH ($PATH)." exit 1 fi export LEIN_JAVA_CMD="${LEIN_JAVA_CMD:-${JAVA_CMD:-java}}" if [[ -z "${DRIP_INIT+x}" && "$(basename "$LEIN_JAVA_CMD")" == *drip* ]]; then export DRIP_INIT="$(printf -- '-e\n(require (quote leiningen.repl))')" export DRIP_INIT_CLASS="clojure.main" fi # Support $JAVA_OPTS for backwards-compatibility. export JVM_OPTS="${JVM_OPTS:-"$JAVA_OPTS"}" # Handle jline issue with cygwin not propagating OSTYPE through java subprocesses: https://github.com/jline/jline2/issues/62 cygterm=false if $cygwin; then case "$TERM" in rxvt* | xterm* | vt*) cygterm=true ;; esac fi if $cygterm; then LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Djline.terminal=jline.UnixTerminal" stty -icanon min 1 -echo > /dev/null 2>&1 fi # TODO: investigate http://skife.org/java/unix/2011/06/20/really_executable_jars.html # If you're packaging this for a package manager (.deb, homebrew, etc) # you need to remove the self-install and upgrade functionality or see lein-pkg. if [ "$1" = "self-install" ]; then if [ -r "$BIN_DIR/../src/leiningen/version.clj" ]; then cat <<-'EOS' 1>&2 Running self-install from a checkout is not supported. See CONTRIBUTING.md for SNAPSHOT-specific build instructions. EOS exit 1 fi msg "Manual self-install is deprecated; it will run automatically when necessary." self_install elif [ "$1" = "upgrade" ] || [ "$1" = "downgrade" ]; then if [ "$LEIN_DIR" != "" ]; then msg "The upgrade task is not meant to be run from a checkout." exit 1 fi if [ $SNAPSHOT = "YES" ]; then cat <<-'EOS' 1>&2 The upgrade task is only meant for stable releases. See the "Bootstrapping" section of CONTRIBUTING.md. EOS exit 1 fi if [ ! -w "$SCRIPT" ]; then msg "You do not have permission to upgrade the installation in $SCRIPT" exit 1 else TARGET_VERSION="${2:-stable}" echo "The script at $SCRIPT will be upgraded to the latest $TARGET_VERSION version." echo -n "Do you want to continue [Y/n]? " read RESP case "$RESP" in y|Y|"") echo msg "Upgrading..." TARGET="/tmp/lein-${$}-upgrade" if $cygwin; then TARGET=$(cygpath -w "$TARGET") fi LEIN_SCRIPT_URL="https://github.com/technomancy/leiningen/raw/$TARGET_VERSION/bin/lein" $HTTP_CLIENT "$TARGET" "$LEIN_SCRIPT_URL" if [ $? == 0 ]; then cmp -s "$TARGET" "$SCRIPT" if [ $? == 0 ]; then msg "Leiningen is already up-to-date." fi mv "$TARGET" "$SCRIPT" && chmod +x "$SCRIPT" unset CLASSPATH exec "$SCRIPT" version else download_failed_message "$LEIN_SCRIPT_URL" fi;; *) msg "Aborted." exit 1;; esac fi else if $cygwin; then # When running on Cygwin, use Windows-style paths for java ORIGINAL_PWD=$(cygpath -w "$ORIGINAL_PWD") fi # apply context specific CLASSPATH entries if [ -f .lein-classpath ]; then add_path CLASSPATH "$(cat .lein-classpath)" fi if [ -n "$DEBUG" ]; then msg "Leiningen's classpath: $CLASSPATH" fi if [ -r .lein-fast-trampoline ]; then export LEIN_FAST_TRAMPOLINE='y' fi if [ "$LEIN_FAST_TRAMPOLINE" != "" ] && [ -r project.clj ]; then INPUTS="$* $(cat project.clj) $LEIN_VERSION $(test -f "$LEIN_HOME/profiles.clj" && cat "$LEIN_HOME/profiles.clj")" if command -v shasum >/dev/null 2>&1; then SUM="shasum" elif command -v sha1sum >/dev/null 2>&1; then SUM="sha1sum" else command_not_found "sha1sum or shasum" fi INPUT_CHECKSUM=$(echo "$INPUTS" | $SUM | cut -f 1 -d " ") # Just don't change :target-path in project.clj, mkay? TRAMPOLINE_FILE="target/trampolines/$INPUT_CHECKSUM" else if hash mktemp 2>/dev/null; then # Check if mktemp is available before using it TRAMPOLINE_FILE="$(mktemp /tmp/lein-trampoline-XXXXXXXXXXXXX)" else TRAMPOLINE_FILE="/tmp/lein-trampoline-$$" fi trap 'rm -f $TRAMPOLINE_FILE' EXIT fi if $cygwin; then TRAMPOLINE_FILE=$(cygpath -w "$TRAMPOLINE_FILE") fi if [ "$INPUT_CHECKSUM" != "" ] && [ -r "$TRAMPOLINE_FILE" ]; then if [ -n "$DEBUG" ]; then msg "Fast trampoline with $TRAMPOLINE_FILE." fi exec sh -c "exec $(cat "$TRAMPOLINE_FILE")" else export TRAMPOLINE_FILE "$LEIN_JAVA_CMD" \ -Dfile.encoding=UTF-8 \ -Dmaven.wagon.http.ssl.easy=false \ -Dmaven.wagon.rto=10000 \ $LEIN_JVM_OPTS \ -Dleiningen.input-checksum="$INPUT_CHECKSUM" \ -Dleiningen.original.pwd="$ORIGINAL_PWD" \ -Dleiningen.script="$SCRIPT" \ -classpath "$CLASSPATH" \ clojure.main -m leiningen.core.main "$@" EXIT_CODE=$? if $cygterm ; then stty icanon echo > /dev/null 2>&1 fi if [ -r "$TRAMPOLINE_FILE" ] && [ "$LEIN_TRAMPOLINE_WARMUP" = "" ]; then TRAMPOLINE="$(cat "$TRAMPOLINE_FILE")" if [ "$INPUT_CHECKSUM" = "" ]; then # not using fast trampoline rm "$TRAMPOLINE_FILE" fi if [ "$TRAMPOLINE" = "" ]; then exit $EXIT_CODE else exec sh -c "exec $TRAMPOLINE" fi else exit $EXIT_CODE fi fi fi leiningen-2.9.1/bin/lein-pkg000066400000000000000000000106371343535564500157200ustar00rootroot00000000000000#!/bin/bash # This variant of the lein script is meant for downstream packagers. # It has all the cross-platform stuff stripped out as well as the # logic for running from a source checkout and self-install/upgrading. export LEIN_VERSION="2.9.1" # cd to the project root, if applicable NOT_FOUND=1 ORIGINAL_PWD="$PWD" while [ ! -r "$PWD/project.clj" ] && [ "$PWD" != "/" ] && [ $NOT_FOUND -ne 0 ]; do cd .. if [ "$(dirname "$PWD")" = "/" ]; then NOT_FOUND=0 cd "$ORIGINAL_PWD" fi done if [[ "$CLASSPATH" != "" ]]; then echo "WARNING: You have \$CLASSPATH set, probably by accident." echo "It is strongly recommended to unset this before proceeding." fi # User init export LEIN_HOME="${LEIN_HOME:-"$HOME/.lein"}" # Support $JAVA_OPTS for backwards-compatibility. JVM_OPTS=${JVM_OPTS:-"$JAVA_OPTS"} JAVA_CMD=${JAVA_CMD:-"java"} for f in "/etc/leinrc" "$LEIN_HOME/leinrc" ".leinrc"; do if [ -e "$f" ]; then source "$f" fi done export LEIN_JVM_OPTS="${LEIN_JVM_OPTS-"-Xverify:none -XX:+TieredCompilation -XX:TieredStopAtLevel=1"}" grep -E -q '^\s*:eval-in\s+:classloader\s*$' project.clj 2> /dev/null && LEIN_JVM_OPTS="${LEIN_JVM_OPTS:-'-Xms64m -Xmx512m'}" # If you're not using an uberjar you'll need to list each dependency # and add them individually to the classpath/bootclasspath as well. LEIN_JAR=/usr/share/java/leiningen-$LEIN_VERSION-standalone.jar # Do not use installed leiningen jar during self-compilation if ! { [ "$1" = "compile" ] && grep -qsE 'defproject leiningen[[:space:]]+"[[:digit:].]+"' \ project.clj ;}; then CLASSPATH="$CLASSPATH":"$LEIN_JAR" if [ "$LEIN_USE_BOOTCLASSPATH" != "no" ]; then LEIN_JVM_OPTS="-Xbootclasspath/a:$LEIN_JAR $LEIN_JVM_OPTS" fi fi # apply context specific CLASSPATH entries if [ -f .lein-classpath ]; then CLASSPATH="$(cat .lein-classpath):$CLASSPATH" fi if [ -n "$DEBUG" ]; then echo "Leiningen's classpath: $CLASSPATH" fi # Which Java? export JAVA_CMD="${JAVA_CMD:-"java"}" export LEIN_JAVA_CMD="${LEIN_JAVA_CMD:-$JAVA_CMD}" if [[ "$(basename "$LEIN_JAVA_CMD")" == *drip* ]]; then export DRIP_INIT="$(printf -- '-e\n(require (quote leiningen.repl))')" fi # Support $JAVA_OPTS for backwards-compatibility. export JVM_OPTS="${JVM_OPTS:-"$JAVA_OPTS"}" function command_not_found { >&2 echo "Leiningen couldn't find $1 in your \$PATH ($PATH), which is required." exit 1 } if [ -r .lein-fast-trampoline ]; then export LEIN_FAST_TRAMPOLINE='y' fi if [ "$LEIN_FAST_TRAMPOLINE" != "" ] && [ -r project.clj ]; then INPUTS="$* $(cat project.clj) $(test -f "$LEIN_HOME/profiles.clj" && cat "$LEIN_HOME/profiles.clj")" if command -v shasum >/dev/null 2>&1; then SUM="shasum" elif command -v sha1sum >/dev/null 2>&1; then SUM="sha1sum" else command_not_found "sha1sum or shasum" fi INPUT_CHECKSUM=$(echo "$INPUTS" | $SUM | cut -f 1 -d " ") # Just don't change :target-path in project.clj, mkay? TRAMPOLINE_FILE="target/trampolines/$INPUT_CHECKSUM" else TRAMPOLINE_FILE="$(mktemp /tmp/lein-trampoline-XXXXXXXXXXXXX)" trap 'rm -f $TRAMPOLINE_FILE' EXIT fi if [ "$1" = "upgrade" ]; then echo "This version of Leiningen was installed with a package manager, but" echo "the upgrade task is intended for manual installs. Please use your" echo "package manager's built-in upgrade facilities instead." exit 1 fi if [ "$INPUT_CHECKSUM" != "" ] && [ -r "$TRAMPOLINE_FILE" ]; then if [ -n "$DEBUG" ]; then echo "Fast trampoline with $TRAMPOLINE_FILE." fi exec sh -c "exec $(cat $TRAMPOLINE_FILE)" else export TRAMPOLINE_FILE "$LEIN_JAVA_CMD" \ -Dfile.encoding=UTF-8 \ -Dmaven.wagon.http.ssl.easy=false \ -Dmaven.wagon.rto=10000 \ $LEIN_JVM_OPTS \ -Dleiningen.input-checksum="$INPUT_CHECKSUM" \ -Dleiningen.original.pwd="$ORIGINAL_PWD" \ -Dleiningen.script="$0" \ -classpath "$CLASSPATH" \ clojure.main -m leiningen.core.main "$@" EXIT_CODE=$? if [ -r "$TRAMPOLINE_FILE" ] && [ "$LEIN_TRAMPOLINE_WARMUP" = "" ]; then TRAMPOLINE="$(cat "$TRAMPOLINE_FILE")" if [ "$INPUT_CHECKSUM" = "" ]; then # not using fast trampoline rm "$TRAMPOLINE_FILE" fi if [ "$TRAMPOLINE" = "" ]; then exit $EXIT_CODE else exec sh -c "exec $TRAMPOLINE" fi else exit $EXIT_CODE fi fi leiningen-2.9.1/bin/lein-sdkman000077500000000000000000000141371343535564500164160ustar00rootroot00000000000000#!/usr/bin/env bash # This variant of the lein script is meant for consumption by SDKMAN! # (i.e. a script which supports all platforms with bash installed) export LEIN_VERSION="2.9.1" if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then delimiter=";" else delimiter=":" fi if [[ "$OSTYPE" == "cygwin" ]]; then cygwin=true else cygwin=false fi function command_not_found { >&2 echo "Leiningen couldn't find $1 in your \$PATH ($PATH), which is required." exit 1 } function make_native_path { # ensure we have native paths if $cygwin && [[ "$1" == /* ]]; then echo -n "$(cygpath -wp "$1")" elif [[ "$OSTYPE" == "msys" && "$1" == /?/* ]]; then echo -n "$(sh -c "(cd $1 2 \(.*\)$') if expr "$link" : '/.*' > /dev/null; then SCRIPT="$link" else SCRIPT="$(dirname "$SCRIPT"$)/$link" fi done BIN_DIR="$(dirname "$SCRIPT")" # LEIN_JAR is slightly different in sdkman because it's bundled with the jar LEIN_JAR="$(dirname "$BIN_DIR")/lib/leiningen-$LEIN_VERSION-standalone.jar" ## echo $LEIN_JAR ## exit 1 export LEIN_JVM_OPTS="${LEIN_JVM_OPTS-"-Xverify:none -XX:+TieredCompilation -XX:TieredStopAtLevel=1"}" # When :eval-in :classloader we need more memory grep -E -q '^\s*:eval-in\s+:classloader\s*$' project.clj 2> /dev/null && \ export LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Xms64m -Xmx512m" add_path CLASSPATH "$LEIN_JAR" if [ "$LEIN_USE_BOOTCLASSPATH" != "no" ]; then LEIN_JVM_OPTS="-Xbootclasspath/a:$LEIN_JAR $LEIN_JVM_OPTS" fi if [ ! -x "$JAVA_CMD" ] && ! type -f java >/dev/null then >&2 echo "Leiningen couldn't find 'java' executable, which is required." >&2 echo "Please either set JAVA_CMD or put java (>=1.6) in your \$PATH ($PATH)." exit 1 fi export LEIN_JAVA_CMD="${LEIN_JAVA_CMD:-${JAVA_CMD:-java}}" if [[ -z "${DRIP_INIT+x}" && "$(basename "$LEIN_JAVA_CMD")" == *drip* ]]; then export DRIP_INIT="$(printf -- '-e\n(require (quote leiningen.repl))')" export DRIP_INIT_CLASS="clojure.main" fi # Support $JAVA_OPTS for backwards-compatibility. export JVM_OPTS="${JVM_OPTS:-"$JAVA_OPTS"}" # Handle jline issue with cygwin not propagating OSTYPE through java subprocesses: https://github.com/jline/jline2/issues/62 cygterm=false if $cygwin; then case "$TERM" in rxvt* | xterm* | vt*) cygterm=true ;; esac fi if $cygterm; then LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Djline.terminal=jline.UnixTerminal" stty -icanon min 1 -echo > /dev/null 2>&1 fi if $cygwin; then # When running on Cygwin, use Windows-style paths for java ORIGINAL_PWD=$(cygpath -w "$ORIGINAL_PWD") fi # apply context specific CLASSPATH entries if [ -f .lein-classpath ]; then add_path CLASSPATH "$(cat .lein-classpath)" fi if [ -n "$DEBUG" ]; then echo "Leiningen's classpath: $CLASSPATH" fi if [ -r .lein-fast-trampoline ]; then export LEIN_FAST_TRAMPOLINE='y' fi if [ "$LEIN_FAST_TRAMPOLINE" != "" ] && [ -r project.clj ]; then INPUTS="$* $(cat project.clj) $LEIN_VERSION $(test -f "$LEIN_HOME/profiles.clj" && cat "$LEIN_HOME/profiles.clj")" if command -v shasum >/dev/null 2>&1; then SUM="shasum" elif command -v sha1sum >/dev/null 2>&1; then SUM="sha1sum" else command_not_found "sha1sum or shasum" fi INPUT_CHECKSUM=$(echo "$INPUTS" | $SUM | cut -f 1 -d " ") # Just don't change :target-path in project.clj, mkay? TRAMPOLINE_FILE="target/trampolines/$INPUT_CHECKSUM" else if hash mktemp 2>/dev/null; then # Check if mktemp is available before using it TRAMPOLINE_FILE="$(mktemp /tmp/lein-trampoline-XXXXXXXXXXXXX)" else TRAMPOLINE_FILE="/tmp/lein-trampoline-$$" fi trap "rm -f $TRAMPOLINE_FILE" EXIT fi if $cygwin; then TRAMPOLINE_FILE=$(cygpath -w "$TRAMPOLINE_FILE") fi if [ "$INPUT_CHECKSUM" != "" ] && [ -r "$TRAMPOLINE_FILE" ]; then if [ -n "$DEBUG" ]; then echo "Fast trampoline with $TRAMPOLINE_FILE." fi exec sh -c "exec $(cat "$TRAMPOLINE_FILE")" else export TRAMPOLINE_FILE "$LEIN_JAVA_CMD" \ -Dfile.encoding=UTF-8 \ -Dmaven.wagon.http.ssl.easy=false \ -Dmaven.wagon.rto=10000 \ $LEIN_JVM_OPTS \ -Dleiningen.input-checksum="$INPUT_CHECKSUM" \ -Dleiningen.original.pwd="$ORIGINAL_PWD" \ -Dleiningen.script="$SCRIPT" \ -classpath "$CLASSPATH" \ clojure.main -m leiningen.core.main "$@" EXIT_CODE=$? if $cygterm ; then stty icanon echo > /dev/null 2>&1 fi if [ -r "$TRAMPOLINE_FILE" ] && [ "$LEIN_TRAMPOLINE_WARMUP" = "" ]; then TRAMPOLINE="$(cat "$TRAMPOLINE_FILE")" if [ "$INPUT_CHECKSUM" = "" ]; then # not using fast trampoline rm "$TRAMPOLINE_FILE" fi if [ "$TRAMPOLINE" = "" ]; then exit $EXIT_CODE else exec sh -c "exec $TRAMPOLINE" fi else exit $EXIT_CODE fi fi leiningen-2.9.1/bin/lein.bat000077500000000000000000000341431343535564500157070ustar00rootroot00000000000000@echo off setLocal EnableExtensions EnableDelayedExpansion set LEIN_VERSION=2.9.1 if "%LEIN_VERSION:~-9%" == "-SNAPSHOT" ( set SNAPSHOT=YES ) else ( set SNAPSHOT=NO ) set ORIGINAL_PWD=%CD% :: If ORIGINAL_PWD ends with a backslash (such as C:\), :: we need to escape it with a second backslash. if "%ORIGINAL_PWD:~-1%x" == "\x" set "ORIGINAL_PWD=%ORIGINAL_PWD%\" call :FIND_DIR_CONTAINING_UPWARDS project.clj if "%DIR_CONTAINING%" neq "" cd "%DIR_CONTAINING%" :: LEIN_JAR and LEIN_HOME variables can be set manually. :: Only set LEIN_JAR manually if you know what you are doing. :: Having LEIN_JAR pointing to one version of Leiningen as well as :: having a different version in PATH has been known to cause problems. if "x%LEIN_HOME%" == "x" ( set LEIN_HOME=!USERPROFILE!\.lein ) SET RC=1 if "x%LEIN_JAR%" == "x" set "LEIN_JAR=!LEIN_HOME!\self-installs\leiningen-!LEIN_VERSION!-standalone.jar" if "%1" == "self-install" goto SELF_INSTALL if "%1" == "upgrade" goto UPGRADE if "%1" == "downgrade" goto UPGRADE if not exist "%~dp0..\src\leiningen\version.clj" goto RUN_NO_CHECKOUT :: Running from source checkout. call :SET_LEIN_ROOT "%~dp0.." set "bootstrapfile=!LEIN_ROOT!\leiningen-core\.lein-bootstrap" rem in .lein-bootstrap there is only one line where each path is concatenated to each other via a semicolon, there's no semicolon at the end rem each path is NOT inside double quotes and may contain spaces (even semicolons but this is not supported here) in their names, rem but they won't/cannot contain double quotes " or colons : in their names (at least on windows it's not allowed/won't work) rem tested when folders contain spaces and when LEIN_ROOT contains semicolon if not "x%DEBUG%" == "x" echo LEIN_ROOT=!LEIN_ROOT! rem if not "%LEIN_ROOT:;=%" == "%LEIN_ROOT%" ( rem oddly enough /G:/ should've worked but doesn't where / they say it's console rem findstr is C:\Windows\System32\findstr.exe echo.!LEIN_ROOT! | findstr /C:";" >nul 2>&1 && ( rem aka errorlevel is 0 aka the string ";" was found echo Your folder structure !LEIN_ROOT! contains at least one semicolon in its name echo This is not allowed and would break things with the generated bootstrap file echo Please correct this by renaming the folders to not contain semicolons in their name del !bootstrapfile! >nul 2>&1 echo You'll also have to recreate the bootstrap file just to be sure it has semicolon-free names inside echo the bootstrap file ^(which was just deleted^) is: !bootstrapfile! echo and the info on how to do that is: goto RUN_BOOTSTRAP ) if not exist !bootstrapfile! goto NO_DEPENDENCIES findstr \^" "!bootstrapfile!" >nul 2>&1 if errorlevel 1 goto PARSE_BOOTSTRAPFILE echo double quotes detected inside file: !bootstrapfile! echo this should not be happening goto RUN_BOOTSTRAP :PARSE_BOOTSTRAPFILE rem will proceed to set LEIN_LIBS and surround each path from bootstrap file in double quotes and separate it from others with a semicolon rem the paths inside the bootstrap file do not already contain double quotes but may contain spaces rem note worthy: the following won't work due to a hard 1022bytes limit truncation in the variable that was set rem set /p LEIN_LIBS=nul 2>&1 if NOT ERRORLEVEL 0 goto TRY_WGET set LAST_HTTP_CLIENT=powershell rem By default: Win7 = PS2, Win 8.0 = PS3 (maybe?), Win 8.1 = PS4, Win10 = PS5 powershell -Command "& {param($a,$f) if (($PSVersionTable.PSVersion | Select-Object -ExpandProperty Major) -lt 4) { exit 111; } else { $client = New-Object System.Net.WebClient; [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $client.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials; $client.DownloadFile($a, $f); }}" ""%2"" ""%1"" SET RC=%ERRORLEVEL% goto EXITRC :TRY_WGET call wget --help >nul 2>&1 if NOT ERRORLEVEL 0 goto TRY_CURL set LAST_HTTP_CLIENT=wget call wget -O %1 %2 SET RC=%ERRORLEVEL% goto EXITRC :TRY_CURL call curl --help >nul 2>&1 if NOT ERRORLEVEL 0 GOTO NO_HTTP_CLIENT rem We set CURL_PROXY to a space character below to pose as a no-op argument set LAST_HTTP_CLIENT=curl set CURL_PROXY= if NOT "x%HTTPS_PROXY%" == "x" set CURL_PROXY="-x %HTTPS_PROXY%" call curl %CURL_PROXY% -f -L -o %1 %2 SET RC=%ERRORLEVEL% goto EXITRC :NO_LEIN_JAR echo. echo %LEIN_JAR% can not be found. echo You can try running "lein self-install" echo or change LEIN_JAR environment variable echo or edit lein.bat to set appropriate LEIN_JAR path. echo. goto EXITRC :NO_DEPENDENCIES echo. echo Leiningen is missing its dependencies. :RUN_BOOTSTRAP echo Please run "lein bootstrap" in the leiningen-core/ directory echo with a stable release of Leiningen. See CONTRIBUTING.md for details. echo. goto EXITRC :SELF_INSTALL if exist "%LEIN_JAR%" ( echo %LEIN_JAR% already exists. Delete and retry. goto EXITRC ) for %%f in ("%LEIN_JAR%") do set LEIN_INSTALL_DIR="%%~dpf" if not exist %LEIN_INSTALL_DIR% mkdir %LEIN_INSTALL_DIR% echo Downloading Leiningen now... set LEIN_JAR_URL=https://github.com/technomancy/leiningen/releases/download/%LEIN_VERSION%/leiningen-%LEIN_VERSION%-standalone.zip call :DownloadFile "%LEIN_JAR%.pending" "%LEIN_JAR_URL%" SET RC=%ERRORLEVEL% if not %RC% == 0 goto DOWNLOAD_FAILED if not exist "%LEIN_JAR%.pending" goto DOWNLOAD_FAILED move /y "%LEIN_JAR%.pending" "%LEIN_JAR%" >nul 2>&1 SET RC=%ERRORLEVEL% goto EXITRC :DOWNLOAD_FAILED SET RC=3 if "%ERRORLEVEL%" == "111" ( echo. echo You seem to be using an old version of PowerShell that echo can't download files via TLS 1.2. echo Please upgrade your PowerShell to at least version 4.0, e.g. via echo https://www.microsoft.com/en-us/download/details.aspx?id=50395 echo. echo Alternatively you can manually download echo %LEIN_JAR_URL% echo and save it as echo %LEIN_JAR% echo. echo If you have "curl" or "wget" you can try setting the HTTP_CLIENT echo variable, but the TLS problem might still persist. echo. echo a^) set HTTP_CLIENT=wget -O echo b^) set HTTP_CLIENT=curl -f -L -o echo. echo NOTE: Make sure to *not* add double quotes when setting the value echo of HTTP_CLIENT goto EXITRC ) SET RC=3 del "%LEIN_JAR%.pending" >nul 2>&1 echo. echo Failed to download %LEIN_JAR_URL% echo. echo It is possible that the download failed due to "powershell", echo "curl" or "wget"'s inability to retrieve GitHub's security certificate. echo. if "%LAST_HTTP_CLIENT%" == "powershell" ( echo The PowerShell failed to download the latest Leiningen version. echo Try to use "curl" or "wget" to download Leiningen by setting up echo the HTTP_CLIENT environment variable with one of the following echo values: echo. echo a^) set HTTP_CLIENT=wget -O echo b^) set HTTP_CLIENT=curl -f -L -o echo. echo NOTE: Make sure to *not* add double quotes when setting the value echo of HTTP_CLIENT ) if "%LAST_HTTP_CLIENT%" == "curl" ( echo Curl failed to download the latest Leiningen version. echo Try to use "wget" to download Leiningen by setting up echo the HTTP_CLIENT environment variable with one of the following echo values: echo. echo a^) set HTTP_CLIENT=wget -O echo. echo NOTE: Make sure to *not* add double quotes when setting the value echo of HTTP_CLIENT echo. echo If neither curl nor wget can download Leiningen, please seek echo for help on Leiningen's GitHub project issues page. ) if "%LAST_HTTP_CLIENT%" == "wget" ( echo Curl failed to download the latest Leiningen version. echo Try to use "wget" to download Leiningen by setting up echo the HTTP_CLIENT environment variable with one of the following echo values: echo. echo. a^) set HTTP_CLIENT=curl -f -L -o echo. echo NOTE: make sure *not* to add double quotes to set the value of echo HTTP_CLIENT echo. echo If neither curl nor wget can download Leiningen, please seek echo for help on Leiningen's GitHub project issues page. ) if %SNAPSHOT% == YES echo See README.md for SNAPSHOT build instructions. echo. goto EOF :UPGRADE set LEIN_BAT=%~dp0%~nx0 set TARGET_VERSION=%2 if "x%2" == "x" set TARGET_VERSION=stable echo The script at %LEIN_BAT% will be upgraded to the latest %TARGET_VERSION% version. set /P ANSWER=Do you want to continue (Y/N)? if /i {%ANSWER%}=={y} goto YES_UPGRADE if /i {%ANSWER%}=={yes} goto YES_UPGRADE echo Aborted. goto EXITRC :YES_UPGRADE echo Downloading latest Leiningen batch script... set LEIN_BAT_URL=https://github.com/technomancy/leiningen/raw/%TARGET_VERSION%/bin/lein.bat set TEMP_BAT=%~dp0temp-lein-%RANDOM%%RANDOM%.bat call :DownloadFile "%LEIN_BAT%.pending" "%LEIN_BAT_URL%" if ERRORLEVEL 0 goto EXEC_UPGRADE del "%LEIN_BAT%.pending" >nul 2>&1 echo Failed to download %LEIN_BAT_URL% goto EXITRC :EXEC_UPGRADE move /y "%LEIN_BAT%.pending" "%TEMP_BAT%" >nul 2>&1 echo. echo Upgrading... set LEIN_JAR= call "%TEMP_BAT%" self-install ( rem This is self-modifying batch code. Use brackets to pre-load the exit command. rem This way, script execution does not depend on whether the replacement script rem has that command at the *very same* file position as the calling batch file. move /y "%TEMP_BAT%" "%LEIN_BAT%" >nul 2>&1 exit /B %ERRORLEVEL% ) :NO_HTTP_CLIENT echo. echo ERROR: Neither PowerShell, Wget, or Curl could be found. echo Make sure at least one of these tools is installed echo and is in PATH. You can get them from URLs below: echo. echo PowerShell: "http://www.microsoft.com/powershell" rem echo Wget: "http://users.ugent.be/~bpuype/wget/" rem Note: Stale URL. HTTP 404. rem Alternative: wget64.exe compiled by J. Simoncic, rename to wget.exe rem MD5 1750c130c5daca8b347d3f7e34824c9b rem Check: https://www.virustotal.com/en/file/abf507f8240ed41aac74c9df6de558c88c2f11d7770f02.8.4-SNAPSHOT5f1cc544b9c08b/analysis/ echo Wget: "https://eternallybored.org/misc/wget/" echo Curl: "http://curl.haxx.se/dlwiz/?type=bin&os=Win32&flav=-&ver=2000/XP" echo. goto EXITRC :SET_LEIN_ROOT set LEIN_ROOT=%~f1 goto EOF :: Find directory containing filename supplied in first argument :: looking in current directory, and looking up the parent :: chain until we find it, or run out :: returns result in %DIR_CONTAINING% :: empty string if we don't find it :FIND_DIR_CONTAINING_UPWARDS set DIR_CONTAINING=%CD% set LAST_DIR= :LOOK_AGAIN if "%DIR_CONTAINING%" == "%LAST_DIR%" ( :: didn't find it set DIR_CONTAINING= goto EOF ) if EXIST "%DIR_CONTAINING%\%1" ( :: found it - use result in DIR_CONTAINING goto EOF ) set LAST_DIR=%DIR_CONTAINING% call :GET_PARENT_PATH "%DIR_CONTAINING%\.." set DIR_CONTAINING=%PARENT_PATH% goto LOOK_AGAIN :GET_PARENT_PATH set PARENT_PATH=%~f1 goto EOF :RUN :: We need to disable delayed expansion here because the %* variable :: may contain bangs (as in test!). There may also be special :: characters inside the TRAMPOLINE_FILE. setLocal DisableDelayedExpansion set "TRAMPOLINE_FILE=%TEMP%\lein-trampoline-%RANDOM%.bat" del "%TRAMPOLINE_FILE%" >nul 2>&1 set ERRORLEVEL= set RC=0 "%LEIN_JAVA_CMD%" -client %LEIN_JVM_OPTS% ^ -Dclojure.compile.path="%DIR_CONTAINING%/target/classes" ^ -Dleiningen.original.pwd="%ORIGINAL_PWD%" ^ -cp "%CLASSPATH%" clojure.main -m leiningen.core.main %* SET RC=%ERRORLEVEL% if not %RC% == 0 goto EXITRC if not exist "%TRAMPOLINE_FILE%" goto EOF call "%TRAMPOLINE_FILE%" del "%TRAMPOLINE_FILE%" >nul 2>&1 goto EOF :PROCESSPATH rem will surround each path with double quotes before appending it to LEIN_LIBS for /f "tokens=1* delims=;" %%a in ("%tmpline%") do ( set LEIN_LIBS=!LEIN_LIBS!"%%a"; set tmpline=%%b ) if not "%tmpline%" == "" goto PROCESSPATH goto EOF :EXITRC exit /B %RC% :EOF leiningen-2.9.1/bin/lein.cmd000066400000000000000000000001601343535564500156710ustar00rootroot00000000000000@echo off setlocal set ps1=%~dpn0.ps1 shift powershell -NoProfile -ExecutionPolicy Bypass -File "%ps1%" %* leiningen-2.9.1/bin/lein.ps1000066400000000000000000000151671343535564500156460ustar00rootroot00000000000000<# .Synopsis Leiningen bootstrap. .Parameter Command The command to pass to leiningen. .Notes This is a very literal port of lein.bat to PowerShell. TODO: - Determine which (if any) environment variables are used from within Leiningen/Clojure and convert the rest to local- or script-scoped variables. - Probably should parse the version from the newest .jar filename, rather than hard-code it and search for the .jar file from it. - Further reduce/simplify/refactor away from batch-file idioms toward idiomatic PowerShell. .Link https://leiningen.org/ #> #require -version 3 [CmdletBinding(SupportsShouldProcess=$true)] Param( [Parameter(Position=0,ValueFromRemainingArguments=$true)][string[]]$Command = 'help' ) function Set-ParentLocation([string]$file) { for($dir = [IO.DirectoryInfo]"$PWD"; $dir.Parent; $dir = $dir.Parent) { if(Test-Path (Join-Path $dir.FullName $file) -PathType Leaf) { cd $dir.FullName; break } } } function Initialize-Environment { $env:LEIN_VERSION = '2.9.1' $env:SNAPSHOT = if($env:LEIN_VERSION -like '*-SNAPSHOT'){'YES'}else{'NO'} #TODO: Still needed? $env:ORIGINAL_PWD = $PWD -replace '\\$','\\' Set-ParentLocation project.clj if(!$env:LEIN_HOME) {$env:LEIN_HOME = "$env:USERPROFILE\.lein"} if(!$env:LEIN_JAR) {$env:LEIN_JAR = "$env:LEIN_HOME\self-installs\leiningen-$env:LEIN_VERSION-standalone.jar"} if($PSVersionTable.PSVersion.Major -gt 5) { if(!($([System.Net.WebProxy]::new()).IsBypassed('https://github.com/'))) { $proxy = $([System.Net.WebProxy]::new()).GetProxy('https://github.com/') Write-Verbose "Using proxy: $proxy" $Script:PSBoundParameters = @{ 'Invoke-WebRequest:Proxy' = $proxy 'Invoke-WebRequest:ProxyUseDefaultCredentials' = $true } } } else { if(!([Net.WebRequest]::DefaultWebProxy.IsBypassed('https://github.com/'))) { $proxy = [Net.WebRequest]::DefaultWebProxy.GetProxy('https://github.com/') Write-Verbose "Using proxy: $proxy" $Script:PSBoundParameters = @{ 'Invoke-WebRequest:Proxy' = $proxy 'Invoke-WebRequest:ProxyUseDefaultCredentials' = $true } } } } function Use-ClassPath([string]$Value) { $env:CLASSPATH = if(!(Test-Path .lein-classpath -PathType Leaf)) {$Value} else {"$(gc .lein-classpath |? {$_} |select -Last 1);$Value"} } function Initialize-Binary { if(!(Test-Path $env:LEIN_JAR -PathType Leaf)) {throw "$env:LEIN_JAR cannot be found. Try running 'lein self-install' or change the LEIN_JAR environment variable."} Use-ClassPath $env:LEIN_JAR } function Initialize-Source { $env:LEIN_ROOT = $PSScriptRoot $env:bootstrapfile = "$env:LEIN_ROOT\leiningen-core\.lein-bootstrap" Write-Verbose "LEIN_ROOT=$env:LEIN_ROOT" if($env:bootstrapfile -like '*;*') #TODO: Still important? {throw "bootstrap file ($env:bootstrapfile) should not contain semicolons!"} if(!(Test-Path $env:bootstrapfile -PathType Leaf)) {throw @' Leiningen is missing its dependencies. Run 'lein bootstrap' in the leiningen-core/ directory with a stable release. See CONTRIBUTING.md for details. '@} if((Get-Content $env:bootstrapfile -raw) -like '*"*') {throw "Double quotes detected inside bootstrap file $env:bootstrapfile!?"} $env:LEIN_LIBS = (Get-Content $env:bootstrapfile |% {$_ -split ';'} |% {"$_"}) -join ';' Write-Verbose "LEIN_LIBS=$env:LEIN_LIBS" Use-ClassPath "$env:LEIN_LIBS;$env:LEIN_ROOT\src;$env:LEIN_ROOT\resources" } function Install-Self { if(Test-Path $env:LEIN_JAR -PathType Leaf) {throw "$env:LEIN_JAR already exists. Delete and retry."} $jardir = ([IO.FileInfo]$env:LEIN_JAR).Directory.FullName if(!(Test-Path $jardir -PathType Container)) {mkdir $jardir |Out-Null} @{ # splatting Invoke-WebRequest due to long URI Uri = "https://github.com/technomancy/leiningen/releases/download/$env:LEIN_VERSION/leiningen-$env:LEIN_VERSION-standalone.zip" OutFile = $env:LEIN_JAR } |% {Write-Progress 'Install-Self' $_.Uri -CurrentOperation "Downloading to $env:LEIN_JAR" ; [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; Invoke-WebRequest @_} Write-Progress 'Install-Self' -Completed } function Update-Self { $targetVersion = if($Command.Length -gt 1) {$Command[1]} else {'stable'} if(!$PSCmdlet.ShouldProcess($PSCommandPath,"upgrade to $targetVersion")) {throw 'Cancelled'} @{ # splatting Invoke-WebRequest due to long URI Uri = "https://github.com/technomancy/leiningen/raw/$targetVersion/bin/lein.cmd" OutFile = "$PSScriptRoot\lein.cmd.pending" } |% {Write-Progress 'Update-Self' $_.Uri -CurrentOperation "Downloading to $PSScriptRoot\lein.cmd.pending" ; Invoke-WebRequest @_} @{ # splatting Invoke-WebRequest due to long URI Uri = "https://github.com/technomancy/leiningen/raw/$targetVersion/bin/lein.ps1" OutFile = "$PSCommandPath.pending" } |% {Write-Progress 'Update-Self' $_.Uri -CurrentOperation "Downloading to $PSCommandPath.pending" -PercentComplete 50 ; Invoke-WebRequest @_} Write-Progress 'Update-Self' -Completed Move-Item "$PSScriptRoot\lein.cmd.pending" "$PSScriptRoot\lein.cmd" -force Move-Item "$PSCommandPath.pending" "$PSCommandPath" -force . "$PSCommandPath" self-install } function Invoke-Java { Write-Verbose "CLASSPATH=$env:CLASSPATH" $env:JAVA_CMD = if($env:JAVA_CMD){$env:JAVA_CMD -replace '\A"|"\Z',''}else{'java'} $env:LEIN_JAVA_CMD = if($env:LEIN_JAVA_CMD){$env:LEIN_JAVA_CMD -replace '\A"|"\Z',''}else{$env:JAVA_CMD} if(!$env:JVM_OPTS){$env:JVM_OPTS = $env:JAVA_OPTS} $JavaArgs = @( '-client',$env:LEIN_JVM_OPTS, "`"-Dclojure.compile.path=$PWD/target/classes`"", #TODO: Add this line only when we're initializing from source "`"-Dleiningen.original.pwd=$env:ORIGINAL_PWD`"", '-cp',$env:CLASSPATH, 'clojure.main', '-m','leiningen.core.main' ) &$env:LEIN_JAVA_CMD @JavaArgs @Command } function Invoke-Leiningen { Initialize-Environment switch($Command[0]) { self-install {Install-Self} upgrade {Update-Self } downgrade {Update-Self } default { if(Test-Path "$PSCommandPath\..\src\leiningen\version.clj" -PathType Leaf) {Initialize-Source} else {Initialize-Binary} Invoke-Java } } } Invoke-Leiningen leiningen-2.9.1/bin/release000077500000000000000000000045121343535564500156300ustar00rootroot00000000000000#!/bin/bash set -e -u RELEASE_VERSION=$1 CURRENT_VERSION="$RELEASE_VERSION-SNAPSHOT" # Would like to use `lein release` here, but we don't have a way to # update the bash scripts or watch for boot slowdowns that way. Maybe # try adding lein-shell? if [ ! -x `which lein-stable` ]; then echo "Install a stable version of Leiningen as lein-stable." exit 1 fi grep $RELEASE_VERSION NEWS.md || (echo "Add $RELEASE_VERSION to NEWS.md" && exit 1) lein vcs assert-committed for f in bin/lein bin/lein-pkg bin/lein-sdkman bin/lein.bat bin/lein.ps1 project.clj leiningen-core/project.clj; do sed -i s/$CURRENT_VERSION/$RELEASE_VERSION/ $f done rm -rf target classes leiningen-core/target leiningen-core/classes leiningen-core/lib rm -rf $HOME/.lein/self-installs/leiningen-$RELEASE_VERSION-standalone.jar LEIN_ROOT=$PWD cd leiningen-core lein-stable do clean, bootstrap cd .. bin/lein uberjar RELEASE_JAR=$PWD/target/leiningen-$RELEASE_VERSION-standalone.jar cp $RELEASE_JAR $HOME/.lein/self-installs cp bin/lein /tmp/lein-$RELEASE_VERSION cd /tmp if [ ! -r test-project ]; then ./lein-$RELEASE_VERSION new test-project fi cd test-project echo "Running a few invocations in order to check boot time..." time ../lein-$RELEASE_VERSION run -m clojure.main/main -e nil time ../lein-$RELEASE_VERSION run -m clojure.main/main -e nil time ../lein-$RELEASE_VERSION run -m clojure.main/main -e nil echo "Check that these are about the same boot times as with the last version." echo "Run this in a project: time lein-stable run -m clojure.main/main -e nil" echo "Proceeding here will publish the new version to the git repo." echo "Are these acceptable times? (~3s) [Y\n]" read CONTINUE case "$CONTINUE" in y|Y|"") gpg -ab $RELEASE_JAR;; *) echo "Aborted." exit 1;; esac cd $LEIN_ROOT git commit -a -m "Release $RELEASE_VERSION" git tag -s $RELEASE_VERSION -m "Release $RELEASE_VERSION" git push && git push --tags && git push origin master:stable echo "Upload $RELEASE_JAR and $RELEASE_JAR.asc to GitHub releases for $RELEASE_VERSION." echo "Copy this version's section of NEWS.md to the GitHub release description." rm -rf target leiningen-core/target echo "Test self-install. If things are good, run this:" echo "$ lein deploy clojars && cd leiningen-core && lein deploy clojars" echo "And announce it on the mailing list." leiningen-2.9.1/doc/000077500000000000000000000000001343535564500142555ustar00rootroot00000000000000leiningen-2.9.1/doc/DEPLOY.md000066400000000000000000000410661343535564500156020ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Deploying Libraries](#deploying-libraries) - [Private Repositories](#private-repositories) - [Static HTTP](#static-http) - [SCP](#scp) - [S3](#s3) - [Artifactory/Nexus/Archiva](#artifactorynexusarchiva) - [Other Non-standard Repository Protocols](#other-non-standard-repository-protocols) - [Authentication](#authentication) - [GPG](#gpg) - [Full-disk Encryption](#full-disk-encryption) - [Credentials in the Environment](#credentials-in-the-environment) - [Deployment](#deployment) - [Releasing Simplified](#releasing-simplified) - [Overriding the default `:release-tasks`](#overriding-the-default-release-tasks) - [Tagging](#tagging) - [Deploying to Maven Central](#deploying-to-maven-central) # Deploying Libraries Getting your library into [Clojars](https://clojars.org) is fairly straightforward as is documented near the end of [the Leiningen tutorial](https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md). However, deploying elsewhere is not always that straightforward. ## Private Repositories There may be times when you want to make a library available to your team without making it public. This is best done by setting up a private repository. There are several types of repositories. ### Static HTTP The simplest kind of private repository is a web server pointed at a directory full of static files. You can use a `file:///` URL in your `:repositories` to deploy that way if the directory is local to the machine on which Leiningen is running. ### SCP If you already have a server set up with your SSH public keys, the `scp` transport is a simple way to publish and consume private dependencies. Place the following inside `defproject`: ```clj :plugins [[org.apache.maven.wagon/wagon-ssh-external "2.6"]] :repositories [["releases" "scp://somerepo.com/home/repo/"]] ``` Then place the following outside the `defproject`: ```clj (cemerick.pomegranate.aether/register-wagon-factory! "scp" #(let [c (resolve 'org.apache.maven.wagon.providers.ssh.external.ScpExternalWagon)] (clojure.lang.Reflector/invokeConstructor c (into-array [])))) ``` It's also possible to deploy to a repository using the `scp` transport and consume from it over `http` if you set up nginx or something similar to serve the repository directory over HTTP. N.B. SCP deploys to Clojars are no longer supported. ### S3 If you don't already have a server running, [Amazon S3](https://aws.amazon.com/s3/) is a low-maintenance choice; you can deploy to S3 buckets using the [S3 wagon private](https://github.com/s3-wagon-private/s3-wagon-private) plugin. ### Artifactory/Nexus/Archiva The most full-featured and complex route is to run a full-fledged repository manager. Both [Artifactory](https://www.jfrog.com/open-source/#os-arti), [Archiva](https://archiva.apache.org/) and [Nexus](http://nexus.sonatype.org/) provide this. They also proxy to other repositories, so you can set `^:replace` metadata on `:repositories` in project.clj, and dependency downloads will speed up by quite a bit since Clojars and Maven Central won't need to be checked. The private server will need to be added to the `:repositories` listing in project.clj. Artifactory, Archiva and Nexus offer separate repositories for snapshots and releases, so you'll want two entries for them: ```clj :repositories [["snapshots" "https://blueant.com/archiva/snapshots"] ["releases" "https://blueant.com/archiva/internal"]] ``` If you are are deploying to a repository that is _only_ used for deployment and never for dependency resolution, then it should be specified in a `:deploy-repositories` slot instead of included in the more general-purpose `:repositories` map; the former is checked by `lein deploy` before the latter. Deployment-only repositories useful across a number of locally developed projects may also be specified in the `:user` profile in `~/.lein/profiles.clj`: ```clj {:user {:deploy-repositories [["internal" "https://blueant.com/archiva/internal"]]}} ``` ### Other Non-standard Repository Protocols If you are deploying to a repository that doesn't use one of the standard protocols (`file:` or `https:`), you may need to provide a wagon factory for that protocol. You can do so by specifying the wagon provider as a plugin dependency: ```clj :plugins [[org.apache.maven.wagon/wagon-webdav-jackrabbit "2.4"]] ``` then registering a wagon factory function at the bottom of your project.clj: ```clj (cemerick.pomegranate.aether/register-wagon-factory! "dav" #(eval '(org.apache.maven.wagon.providers.webdav.WebDavWagon.))) ``` This step is unnecessary for plugins that include explicit Leiningen support like [S3 wagon private](https://github.com/technomancy/s3-wagon-private) and [lein-webdav](https://github.com/tobias/lein-webdav) as these declare their wagons in ways that can be inferred automatically. ## Authentication Deploying and reading from private repositories needs authentication credentials. Check your repository's documentation for details, but you'll usually need to provide a `:username` and `:password` (for a repository) or `:passphrase` (for GPG). Leiningen will prompt you for a password if you haven't set up credentials, but it's convenient to set it so you don't have to re-enter it every time you want to deploy. You will need [gpg](https://www.gnupg.org/) installed and a key pair configured. If you need help with either of those, see the [GPG guide](https://github.com/technomancy/leiningen/blob/stable/doc/GPG.md). ### GPG If you specify a `:creds :gpg` entry in one of your `:repositories` settings maps, Leiningen will decrypt `~/.lein/credentials.clj.gpg` and use that to find the proper credentials for the given repository. ```clj :repositories [["releases" {:url "https://blueant.com/archiva/internal" :creds :gpg}]] ``` First write your credentials map to `~/.lein/credentials.clj` like so: ```clj {#"blueant" {:password "locative1"} #"https://repo.clojars.org" {:username "milgrim" :password "locative1"} "s3p://s3-repo-bucket/releases" {:username "AKIAIN..." :passphrase "1TChrGK4s..."}} ``` Then encrypt it with `gpg`: $ gpg --default-recipient-self -e \ ~/.lein/credentials.clj > ~/.lein/credentials.clj.gpg Remember to delete the plaintext `credentials.clj` once you've encrypted it. Due to a bug in `gpg` you currently need to use `gpg-agent` and have already unlocked your key before Leiningen launches, but with `gpg-agent` you only have to enter your passphrase periodically; it will keep it cached for a given period. Note to windows users: Be sure to download the full version of [Gpg4win](https://gpg4win.org/download.html) and select GPA for installation. You then need to run `gpg-connect-agent /bye` from the command line before starting lein. ### Full-disk Encryption If you use full-disk encryption, it may be safe to store your credentials without using GPG. In this case, you can create an `:auth` profile containing a `:repository-auth` key mapping URL regexes to credentials. Your `~/.lein/profiles.clj` file would look something like this: ```clj {:user {...} :auth {:repository-auth {#"blueant" {:username "milgrim" :password "locative1"}}}} ``` ### Credentials in the Environment Unattended builds can specify `:env` instead of `:gpg` in the repository specification to have credentials looked up in the environment. For example, specifying `:password :env` will cause Leiningen to look up `(System/getenv "LEIN_PASSWORD")` for that value. You can control which environment variable is looked up for each value by using a namespaced keyword, like so: ```clj :repositories [["releases" {:url "https://blueant.com/archiva/internal" :username :env/archiva_username :password :env/archiva_password}]] ``` Finally, you can opt to load credentials from the environment _or_ GPG credentials by using a vector of `:gpg` and `:env/*` values to define the priority of each: ```clj :repositories [["releases" {:url "https://blueant.com/archiva/internal" :username [:gpg :env/archiva_username] :password [:gpg :env/archiva_password]}]] ``` In this example, both `:username` and `:password` will be looked up in `~/.lein/credentials.clj.gpg` first, and only if a value is not available there will the `ARCHIVA_*` env vars be checked. This allows you to avoid creating profiles just to use different credential sources in e.g. a local development environment vs. a centralized build environment. Note that the forms `:env` and `:env/varname` are only supported within the `:repositories` key. Plugins may decide to implement this themselves, but this is not default behaviour. ## Deployment Once you've set up a private repository and configured project.clj appropriately, you can deploy to it: $ lein deploy [repository-name] If the project's current version is a `SNAPSHOT`, it will default to deploying to the `"snapshots"` repository; otherwise it will default to `"releases"`. In order to make `lein deploy` with no argument target Clojars, include this in your `project.clj`: ```clj {:deploy-repositories [["releases" :clojars] ["snapshots" :clojars]]} ``` You can use this to alias any `:repositories` entry; Clojars is just the most common use case. ## Releasing Simplified Once you have your repositories and user credentials configured for deploying, much of the work involved in actually deploying a release version can be tedious and difficult to perform in a consistent fashion from one release to the next. To simplify the release process, there is a `lein release [$LEVEL]` task where `$LEVEL` can be refer to any of `:major`, `:minor`, `:patch`, `:alpha`, `:beta`, or `:rc`. The simplification lies in the list of `:release-tasks` that get run on each call to `lein release`. For example, suppose that your `project.clj` starts off as follows: ```clojure (defproject leiningen "2.4.0-SNAPSHOT" ...) ``` Using the default `:release-tasks` and the following command line: $ lein release :patch The following events will happen: 1. The `change` task is run to remove whatever qualifier is currently on the version in `project.clj`. In this case, `project.clj` should look something like ```(defproject leiningen "2.4.0" ...)```. 2. `vcs` tasks will be run to commit this change and then tag the repository with the `release` version number. 3. The `deploy` task will be the same as if `lein deploy` had been run from the command line. **NOTE** This will require a valid `"releases"` entry either in `:deploy-repositories` or `:repositories` 4. The `change` task is run once more to "bump" the version number in `project.clj`. Which version level is decided by the argument passed to `lein release`, in this case `:patch`. Afterword, `project.clj` will look something like ```(defproject leiningen "2.4.1-SNAPSHOT" ...)```. 5. Finally, `vcs` tasks will be run once more to commit the new change to `project.clj` and then push these two new commits to the default remote repository. The release process will fail if there are uncommitted changes. ### Overriding the default `:release-tasks` You can use the `lein-pprint` plugin to see the default value of `:release-tasks`: ``` $ lein pprint :release-tasks [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] ["vcs" "tag"] ["deploy"] ["change" "version" "leiningen.release/bump-version"] ["vcs" "commit"] ["vcs" "push"]] ``` This `:release-tasks` value can be overridden in `project.clj`. An example might be a case in which you want the default workflow up to `lein deploy` but don't want to automatically bump the version in `project.clj`: ```clojure :release-tasks [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] ["vcs" "tag"] ["deploy"]] ``` The `:release-tasks` vector should have every element be either a task name or a collection in which the first element is a task name and the rest are arguments to that task, just like `:prep-tasks` or `:aliases` entries. Of course, `:release-tasks` doesn't have to look anything like the default, the default is just an assumed convention among most Clojure libraries using Leiningen. Applications will have different requirements that are varied enough that Leiningen doesn't attempt to support them out of the box. If you just want to change the `deploy` step so it goes to Clojars, you don't have to replace the whole `:release-tasks` vector, just set this: ```clojure :deploy-repositories {"releases" {:url "https://repo.clojars.org" :creds :gpg}} ``` ### Committing By default, `["vcs" "commit"]` will commit with the message `"Version "`. You can override that by passing a `format`-ready string to the task, like so: `["vcs" "commit" "Version %s [skip ci]"]`. ### Tagging By default `["vcs" "tag"]` will create a GPG signed tag with your project version number. You can add a tag prefix by passing the prefix after `"tag"`, for example: `["vcs" "tag" "v"]`. You can disable tag signing by passing `--no-sign`, for example: `["vcs" "tag" "v" "--no-sign"]` or `["vcs" "tag" "--no-sign"]`. ## Deploying to Maven Central Deploying your libraries and other artifacts to [Maven Central](https://search.maven.org/) is often desirable. Most tools that use the Maven repository format (including Leiningen, Gradle, sbt, and Maven itself) include Maven Central or one of its mirrors as a default repository for resolving project dependencies. So deploying your libraries to Maven Central offers the widest distribution, especially if your users are likely to be in languages other than Clojure. Thankfully, Leiningen can deploy your libraries to Maven Central, with a few additional bits of configuration. All of the guidance about deploying to private repositories laid out above applies; but, here's a step-by-step recipe from start to finish: 1. Register an account and groupId on `oss.sonatype.org`; refer to [this](https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide) for details on how to get registered (you can ignore most of the info on that page regarding configuring Maven and/or ant, since we'll not be touching those tools). Note that all artifacts you deploy to Sonatype OSS will need to use the groupId(s) you choose, so your project coordinates should be set up to match; e.g.: ```clojure (defproject your.group.id/projectname "x.y.z" ...) ``` 2. Add your credentials for `oss.sonatype.org` to your `~/.lein/credentials.clj.gpg` file. Something like this will do: ```clojure {#"https://oss.sonatype.org/.*" {:username "username" :password "password"}} ``` Refer to the instructions earlier on this page for how to encrypt a plain-text `credentials.clj` using GPG. 3. Add the Sonatype OSS deployment repository endpoints to your project.clj, e.g.: ```clojure :deploy-repositories [["releases" {:url "https://oss.sonatype.org/service/local/staging/deploy/maven2/" :creds :gpg} "snapshots" {:url "https://oss.sonatype.org/content/repositories/snapshots/" :creds :gpg}]] ``` 4. Conform to Sonatype OSS' requirements for uploaded artifacts' `pom.xml` files; all you need to do is make sure the following slots are populated properly in your `project.clj`: ```clojure :description :url :license :scm :pom-addition ``` Examples of OSS-acceptable values for these entries can be seen in this [`project.clj` file](https://github.com/cemerick/piggieback/blob/master/project.clj). Note that all of them should be appropriate for *your* project; blind copy/paste is not appropriate here. 5. Run `lein deploy`. Leiningen will push all of the files it would otherwise send to Clojars or your other private repository to the proper OSS repository (either releases or snapshots depending on whether your project's version number has `-SNAPSHOT` in it or not). 6. If you're deploying a release, log in to `oss.sonatype.org`, and close and release/promote your staged repository. (This manual step will eventually be automated through the use of a plugin.) The release will show up in OSS' releases repository immediately, and sync to Maven Central on the next cycle (~ 1-4 hours usually). leiningen-2.9.1/doc/FAQ.md000066400000000000000000000342121343535564500152100ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [FAQ](#faq) # FAQ **Q:** How do you pronounce Leiningen? **A:** It's LINE-ing-en. ['laɪnɪŋən] **Q:** What's a group ID? How do snapshots work? **A:** See the [tutorial](https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md) for background. **Q:** How should I pick my version numbers? **A:** Use [semantic versioning](http://semver.org) to communicate intentions to downstream users of your library, but don't make assumptions that libraries you use stick with it consistently. Remember that the difference between a breaking change and a bug fix is often subjective. **Q:** What if my project depends on jars that aren't in any repository? **A:** You will need to get them in a repository. The [deploy guide](https://github.com/technomancy/leiningen/blob/stable/doc/DEPLOY.md) explains how to set up a private repository. In general it's easiest to deploy them to a static HTTP server or a private S3 bucket. Once the repo is set up, `lein deploy private-repo com.mycorp/somejar 1.0.0 somejar.jar pom.xml` will push the artifacts out. If you don't have a pom, you can create a dummy project with `lein new` and generate a pom from that. If you are just doing exploratory coding you can deploy to `file:///$HOME/.m2/repository` and the jars will be available locally. **Q:** I want to hack a project and one of its dependencies, but it's annoying to switch between them. **A:** Leiningen provides a feature called *checkout dependencies* to make this smoother. See the [tutorial](https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md) to learn more. **Q:** Is it possible to exclude indirect dependencies? **A:** Yes. Some libraries, such as log4j, depend on projects that are not included in public repositories and unnecessary for basic functionality. Projects listed as `:dependencies` may exclude any of their dependencies by using the `:exclusions` key. See `lein help sample` for details. **Q:** I specified a dependency on version X but am getting version Y; what's up? **A:** One of your dependencies' dependencies has declared a dependency on a hard version range, which overrides your "soft" declaration. Running `lein deps :tree` will identify which of your dependencies are responsible for the version range. You can add an `:exclusions` clause to prevent that from affecting the rest of your dependencies. See `lein help sample` for how exclusions work. You may also want to report a bug with the dependency that uses hard version ranges as they cause all kinds of problems and exhibit unintuitive behaviour. **Q:** I have two dependencies, X and Y, which depends on Z. How is the version of Z decided? **A:** The decision depends on which depth and which order the dependencies come in the `:dependencies` vector: The dependency at the lowest depth will be picked. If there are multiple versions of a single group/artifact at that depth, the first of those will be picked. For instance, in the dependency graph [Z "1.0.9"] [X "1.3.2"] [Z "2.0.1"] the direct dependency (`[Z "1.0.9"]`) is picked, as it is closest to the root. For the dependency graph [X "1.3.2"] [Z "2.0.1"] [Y "1.0.5"] [Z "2.1.3"] the dependency X comes first, and therefore `[Z "2.0.1"]` is picked. If we place Y before X however, `[Z "2.1.3"]` will be picked. Note that this only applies to soft dependencies, and `lein deps :tree` will only warn if the latest version is not chosen. **Q:** I'm behind an HTTP proxy; how can I fetch my dependencies? **A:** Set the `$http_proxy` environment variable in Leiningen 2.x. You can also set `$http_no_proxy` for a list of hosts that should be reached directly, bypassing the proxy. This is a list of patterns separated by `|` and may start or end with a `*` for wildcard, e.g. `localhost|*.mydomain.com`. For Leiningen 1.x versions, see the instructions for [configuring a Maven proxy](https://maven.apache.org/guides/mini/guide-proxies.html) using `~/.m2/settings.xml`. **Q:** What can be done to speed up launch? **A:** The main delay involved in Leiningen comes from starting two JVMs: one for your project and one for Leiningen itself. Most people use a development cycle that involves keeping a single project REPL process running for as long as they're working on that project. Depending on your editor you may be able to do this via its Clojure integration. (See [cider](https://github.com/clojure-emacs/cider) or [fireplace](https://github.com/tpope/vim-fireplace), for example.) Otherwise you can use the basic `lein repl`. **Q:** Version 2.8.0 seems a bit slower; why is that? **A:** We have long used a hack of putting Leiningen on the JVM's bootclasspath to speed up boot time, but the module system in Java 9 breaks this. We have switched to another method of speeding it up (`-Xverify:none`) which gives anywhere from 95% to 70% of the same speed boost depending on the machine on which you're running it. So some users will notice a performance regression. We hope to go back to the old method once Clojure 1.9.0 is released with a workaround, but in the mean time if you are not using Java 9, you can go back to the bootclasspath hack with this setting: export LEIN_USE_BOOTCLASSPATH=y **Q:** Still too slow; what else can make startup faster? **A:** The wiki has a page covering [ways to improve startup time](https://github.com/technomancy/leiningen/wiki/Faster). **Q:** What if I care more about long-term performance than startup time? **A:** Leiningen 2.1.0 onward get a speed boost by disabling optimized compilation (which only benefits long-running processes). This can negatively affect performance in the long run, or lead to inaccurate benchmarking results. If want the JVM to fully optimize, you can switch profiles with `lein with-profiles production run ...`. **Q:** I'm attempting to run a project as a background process (`lein run &`), but the process suspends until it is in the foreground. How do I run a program in the background? **A:** For long-lasting processes, it's better to create an uberjar and run that or use `lein trampoline run &`. For short-lived ones, both `lein run <&- &` and `bash -c "lein run &"` will work fine. **Q:** I'm getting "could not transfer artifact ... peer not authenticated" **A:** This means that either your JVM is not configured with the correct certificate authorities, or you're experiencing a [man-in-the-middle attack](https://github.com/technomancy/leiningen/issues/1028#issuecomment-32732452) on your SSL connection. Leiningen ships with the current Clojars public certificate at the time of this writing, so you should be able to work around problems with your CA by putting `:certificates ["clojars.pem"]` in your `:user` profile, assuming the certificate that ships with Leiningen hasn't expired. **Q:** How do I determine my project's version at runtime? **A:** Leiningen writes a file called `pom.properties` into `target/classes` which contains the version number and current git revision of the project. In previous versions of Leiningen this was only available when running from jar files, but as of 2.4.1 it's available during `lein run ...`, etc. You can read it by running this code (replace "group" and "artifact" with values appropriate to your project): ```clj (with-open [pom-properties-reader (io/reader (io/resource "META-INF/maven/group/artifact/pom.properties"))] (doto (java.util.Properties.) (.load pom-properties-reader))) ``` **Q:** How can I read my project map at runtime? **A:** Usually you do not need the complete project map, only a specific subset of some values. If you want different configuration based on different tasks, then [environ](https://github.com/weavejester/environ) is probably a good fit. If you want information like the project's version number or git revision, read the question and answer above. Generally those solutions are sufficient, but if you need more than this, you should rather read the `project.clj` yourself. The project map changes based on the task you use, and so different tasks (repl, jar, uberjar to name a few) will make it hard to make the testing- and production project map identical. `project.clj` is added as a resource in `META-INF/leiningen/group/artifact/project.clj` (replace "group" and "artifact" with values appropriate to your project). You can read it as follows: ```clj (read-string (slurp (io/resource "META-INF/leiningen/group/artifact/project.clj"))) ``` **Q:** I need to do AOT for an uberjar; can I avoid it during development? **A:** Yes, it is strongly recommended to do AOT only in the uberjar task if possible. But by default the AOT'd files will still be visible during development unless you also change `:target-path` to something like `"target/uberjar"` in the `:uberjar` profile as well. **Q:** Is there a way to use an uberjar without AOT? **A:** As of Leiningen 2.4.0, if you omit `:main` in `project.clj`, your uberjars will use `clojure.main` as their entry point. You can launch with `java -jar my-app-standalone.jar -m my.entry.namespace arg1 arg2 [...]` without any AOT, but it will take longer to launch. **Q:** Why does `lein jar` package some namespaces from dependencies into my jar? **A:** This is likely because you have AOT-compiled namespaces. An AOT-compiled namespace can only depend on AOT-compiled namespaces. Therefore, if you depend on a namespace in a dependency that is not AOT-compiled, it will be AOT-compiled and bundled with the jar. It is strongly recommended not to perform AOT other than during the creation of an uberjar. **Q:** I'd like to have certain config active only on a certain OS. **A:** You can do this by using unquote in the `:dev` profile: ```clj :profiles {:dev [:dev/all ~(leiningen.core.utils/get-os)] :dev/all {...} :linux {...} :windows {...} :macosx {...}} ``` You can also check things like `(System/getProperty "java.specification.version")` to use the JVM version or any other property. **Q:** What does `Received fatal alert: protocol_version` mean when trying to access Clojars? **A:** This usually means your JVM is not configured to use TLSv1.2, which is used by Clojars' CDN. It's strongly recommended to upgrade to at least Java 8, but if this is not feasible, you can fix it by exporting `LEIN_JVM_OPTS=-Dhttps.protocols=TLSv1.2` as an environment variable. **Q:** I get a `java.security.KeyException` or `sun.security.provider.certpath.SunCertPathBuilderException` when running `lein` **A:** The `java.security.KeyException` indicates an ssl error when trying to communicate with the HTTPS server via Java. This could be because you need to update the JDK, or some other package (e.g. with old versions of the nss package). * On Fedora, you might just try running a `sudo yum update` to update all of your packages or `sudo yum update nss`. * On Debian/Ubuntu, `sudo update-ca-certificates -f` might help, or `sudo /var/lib/dpkg/info/ca-certificates-java.postinst configure` * You should also check your system clock and make sure the time is accurate; it's possible to run into SSL connection failures if your clock is way out of sync. * If it still doesn't work, please see if any of [these 'ssl' labelled issues](https://github.com/technomancy/leiningen/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Assl%20) might help **Q:** I got `Tried to use insecure HTTP repository without TLS`, what is that about? **A:** This means your project was configured to download dependencies from a repository that does not use TLS encryption. This is very insecure and exposes you to trivially-executed man-in-the-middle attacks. In the rare event that you don't care about the security of the machines running your project or can ensure that the only http traffic is going out over a trusted network, you can re-enable support for unsafe repositories by putting this in your `project.clj` file: ;; never do this (require 'cemerick.pomegranate.aether) (cemerick.pomegranate.aether/register-wagon-factory! "http" #(org.apache.maven.wagon.providers.http.HttpWagon.)) It's also possible you have a dependency which includes a reference to an insecure repository for retrieving its own dependencies. If this happens it is strongly recommended to add an `:exclusion` and report a bug with the dependency which does this. **Q:** `lein`/`lein.bat` won't download `leiningen-x.y.z-SNAPSHOT.jar` **A:** You probably downloaded `lein`/`lein.bat` from the [master branch](https://github.com/technomancy/leiningen/tree/master/bin). Unless you plan to build leiningen yourself or help develop it, we suggest you use the latest stable version: [lein](https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein)/[lein.bat](https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.bat) **Q:** I have a dependency whose group ID and/or artifact ID starts with a number (which is invalid for symbols in Clojure). How can I add it to my project's dependencies? **A:** As of version 2.8.0, Leiningen supports string dependency names like this: ```clj :dependencies [["net.3scale/3scale-api" "3.0.2"]] ``` Prior to version 2.8.0, this is the workaround: ```clj :dependencies [[~(symbol "net.3scale" "3scale-api") "3.0.2"]] ``` **Q:** I'm getting warnings for implicit hooks or implicit middleware. **A:** Hooks are a deprecated feature where plugins can modify the behavior of built-in Leiningen functionality; they result in situations which can be very difficult to debug and usually point to situations in which the original API is not flexible enough. Leiningen also has a deprecated feature for implicitly loading middleware. Middleware is not deprecated but should now be declared using `:middleware` instead of being auto-detected from plugins. Adding `:implicits false` to `project.clj` will disable all implicit features. leiningen-2.9.1/doc/GPG.md000066400000000000000000000310171343535564500152160ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Using GPG](#using-gpg) - [What is it?](#what-is-it) - [Installing GPG](#installing-gpg) - [Linux](#linux) - [Debian based distributions](#debian-based-distributions) - [Fedora based distributions](#fedora-based-distributions) - [Mac](#mac) - [Windows](#windows) - [Creating a keypair](#creating-a-keypair) - [Listing keys](#listing-keys) - [Publishing your public key](#publishing-your-public-key) - [How Leiningen uses GPG](#how-leiningen-uses-gpg) - [Signing a file](#signing-a-file) - [Overriding the gpg defaults](#overriding-the-gpg-defaults) - [Troubleshooting](#troubleshooting) - [Debian based distributions](#debian-based-distributions-1) - [gpg: can't query passphrase in batch mode](#gpg-cant-query-passphrase-in-batch-mode) - [Mac OSX](#mac-osx) - [Unable to get GPG installed via Homebrew and OSX Keychain to work](#unable-to-get-gpg-installed-via-homebrew-and-osx-keychain-to-work) - [GPG doesn't ask for a passphrase](#gpg-doesnt-ask-for-a-passphrase) - [GPG prompts for passphrase but does not work with Leiningen](#gpg-prompts-for-passphrase-but-does-not-work-with-leiningen) # Using GPG This is an introduction to setting up and using [GPG](https://www.gnupg.org/) keys with [Leiningen](https://leiningen.org) to sign artifacts for publication to [Clojars](https://clojars.org/) and to encrypt repository credentials. There are two versions of GPG available: v1.x and v2.x. For our purposes, they are functionally equivalent. Package managers generally install v2.x as `gpg2`, and v1.x as `gpg`, except for Homebrew which installs v2.x as `gpg`, and v1.x as `gpg1`. By default, Leiningen expects the GPG command to be `gpg`. You're welcome to use any version you like, but this primer will only cover installing v1.x (except under macOS), and has only been tested under v1.x. ## What is it? [GPG](https://www.gnupg.org/) (or Gnu Privacy Guard) is a set of tools for cryptographic key creation/management and encryption/signing of data. If you are unfamiliar with the concepts of public key cryptography, this [Wikipedia entry](https://en.wikipedia.org/wiki/Public-key_cryptography) serves as a good introduction. An important concept to understand in public key cryptography is that you are really dealing with two keys (a *keypair*): one public, the other private (or secret). The public key can be freely shared, and is used by yourself and others to encrypt data that only you, as the holder of the private key, can decrypt. It can also be used to verify the signature of a file, confirming that the file was signed by the holder of the private key, and the contents of the file have not been altered since it was signed. **You should guard your private key and passphrase closely, and share them with no one.** ## Installing GPG ### Linux ##### Debian based distributions Apt uses GPG v1, so it should already be installed. If not: apt-get install gnupg #### Fedora based distributions Fedora and friends may have GPG v2 installed by default, but GPG v1 is available via: yum install gnupg ### Mac There are several options here, depending on which package manager you have installed (if any): 1. via [homebrew](https://brew.sh/): `brew install gnupg2` 2. via [macports](https://www.macports.org/): `port install gnupg2` 3. via a [binary installer](https://www.gpgtools.org/installer/index.html) (this installs gpg2 as gpg) ### Windows [GPG4Win](https://gpg4win.org/) provides a binary installer that provides some possibly useful GUI tools in addition to providing the `gpg` command. ## Creating a keypair Create a keypair with: gpg --gen-key This will prompt you for details about the keypair to be generated, and store the resulting keypair in `~/.gnupg/`. The default key type (RSA and RSA) is fine for our purposes, as is the default keysize (2048). We recommend a validity period of 2 years. You'll be prompted for a passphrase to protect your private key - it's important to use a strong one to help protect the integrity of your key. ## Listing keys GPG stores keys in a keystore located in `~/.gnupg/`. This keystore holds your keypair(s), along with any other public keys you have used. To list all of the public keys in your keystore: gpg --list-keys This will include any public keys you have used, including keys from others (if you've never used GPG before and just created your first keypair, you should just see your own key). The output of the `--list-keys` option will include the id of your public key in the 'pub' line in the key listing (you'll need that id for other commands described here): $ gpg --list-keys ↓↓↓↓↓↓↓↓ pub 2048R/2ADFB13E 2013-03-16 [expires: 2014-03-16] uid Bob Bobson sub 2048R/8D2344D0 2013-03-16 [expires: 2014-03-16] The `--fingerprint` option will act just like `--list-keys`, but will include the fingerprint of each certificate in the output. You can filter the output of the `--fingerprint` option by providing a key id or any substring from the uid (this trick also works for the `--list-keys` option): $ gpg --fingerprint 2ADFB13E pub 2048R/2ADFB13E 2013-03-16 [expires: 2014-03-16] Key fingerprint = 3367 5FD0 D67B 3218 5815 51A3 97D4 06D0 2ADF B13E uid Bob Bobson sub 2048R/8D2344D0 2013-03-16 [expires: 2014-03-16] ## Publishing your public key To make it easier for others that need your public key to find it, you can publish it to a key server with: gpg --send-keys 2ADFB13E # use your id instead This pushes a copy of your public key to one of a cluster of free key servers, and the key is propagated to all of the other servers in the cluster in short order. If your keypair is compromised, you can publish a revocation certificate to the key server to let others know that your key can no longer be trusted for any future signing or encryption. It's a good idea to generate a revocation certificate whenever you create a new keypair, and store it in a safe place. As long as you have that revocation certificate, you can revoke a keypair even if you no longer have the private key. You can generate a revocation certificate with: $ gpg --output 2ADFB13E-revoke.asc --gen-revoke 2ADFB13E Be sure to protect your revocation certificate carefully - anyone who gains access to it can use it to revoke your keypair. The GPG maintainers recommend printing it out and storing the hardcopy in a safe place. To revoke your certificate **when the time comes (not now!)**, do the following: $ gpg --import 2ADFB13E-revoke.asc # ONLY WHEN YOU NEED TO REVOKE $ gpg --send-keys 2ADFB13E # ONLY WHEN YOU NEED TO REVOKE ## How Leiningen uses GPG Leiningen uses GPG for three things: decrypting credential files, signing release artifacts, and signing tags. We'll focus on artifact signing here; for information on credentials encryption/decryption, see the [deploy guide](https://github.com/technomancy/leiningen/blob/stable/doc/DEPLOY.md). Once you are configured to sign releases, signing tags should be straightforward. On some systems you will be prompted for your GPG passphrase when it is needed if you haven't entered it. If yours does not, you can install [Keychain](https://github.com/funtoo/keychain), which provides this functionality portably. ### Signing a file When you deploy a non-SNAPSHOT artifact via the `deploy` task, Leiningen will attempt to create GPG signatures of the jar and pom files. It does so by shelling out to `gpg` and using your default private key to sign each artifact. This will create a signature file for each artifact named by appending `.asc` to the artifact name. Both signatures are then uploaded along with the artifacts. If you're deploying to Clojars, you'll want to provide it with your *public* key (see below) in order that the signatures can be verified. To disable signing of releases, set `:sign-releases` to false in the `:repositories` entry you are targeting. If you do this, everyone who is depending on your library will not be able to confirm that the copy they get has not been tampered with, so this is not recommended. ### Overriding the gpg defaults By default, Leiningen will try to call GPG as `gpg`, which assumes that `gpg` is in your path, and your GPG binary is actually called `gpg`. If either of those are false, you can override the command Leiningen uses for GPG by setting the `LEIN_GPG` environment variable. GPG by default will select the first private key it finds (which will be the first key listed by `gpg --list-secret-keys`). If you have multiple keys and want to sign with one other than first, or want to use specific keys for a particular release repository, you can specify which key to use either globally, per-project, or per-deploy-repository. All three places use the same configuration syntax, it's all about where you put it. You can specify the key by id or by the uid. To set a key globally, add it to your user profile in `~/.lein/profiles.clj`: {:user {... :signing {:gpg-key "2ADFB13E"}}} ;; using the key id To set a key for a particular project, add it to the project definition: (defproject ham-biscuit "0.1.0" ... :signing {:gpg-key "bob@bobsons.net"} ;; using the key uid ...) To set a key for a particular deploy repository, add it to the repository specification in your project definition: (defproject ham-biscuit "0.1.0" ... :deploy-repositories [["releases" {:url "https://blueant.com/archiva/internal/releases" :signing {:gpg-key "2ADFB13E"}}] ["snapshots" "https://blueant.com/archiva/internal/snapshots"]] ...) ## Troubleshooting ### Debian based distributions #### gpg: can't query passphrase in batch mode Could not decrypt credentials from /home/xxx/.lein/credentials.clj.gpg gpg: can't query passphrase in batch mode gpg: decryption failed: secret key not available This error happens with gpg 1.4.12. Make sure that you have `use-agent` option explicitly enabled in `~/.gnupg/gpg.conf`. See gpg option list. You can test whether this solution works with gpg --quiet --batch --decrypt ~/.lein/credentials.clj.gpg If the system asked your passphrase then problem solved. ### Mac OSX #### Unable to get GPG installed via Homebrew and OSX Keychain to work Installing GPG from here instead: https://www.gpgtools.org/installer/index.html #### GPG doesn't ask for a passphrase Make sure that you have "use-agent" option explicitly enabled in ~/.gnupg/gpg.conf. See gpg option list. You can test the config with gpg --quiet --batch --decrypt ~/.lein/credentials.clj.gpg Leiningen should pick it up automatically when the command above works correctly. #### gpg: decryption failed: secret key not available When you run gpg --quiet --batch --decrypt ~/.lein/credentials.clj.gpg you get the error message gpg: decryption failed: secret key not available try running it without `--quiet` gpg --use-agent --decrypt ~/.lein/credentials.clj.gpg If you get gpg: encrypted with RSA key, ID DEAD8F70 gpg: decryption failed: secret key not available run `gpg -k` and check that `DEAD8F70` is in the known keys list. If it isn't, `~/.lein/credentials.clj.gpg` may have been encrypted with a different key. ### GPG prompts for passphrase but does not work with Leiningen gpg --quiet --batch --decrypt ~/.lein/credentials.clj.gpg It's hanging for a while after executing lein repl and then prints out these messages: $ lein repl Could not decrypt credentials from /Users/xxx/.lein/credentials.clj.gpg pinentry-curses: no LC_CTYPE known - assuming UTF-8 pinentry-curses: no LC_CTYPE known - assuming UTF-8 pinentry-curses: no LC_CTYPE known - assuming UTF-8 pinentry-curses: no LC_CTYPE known - assuming UTF-8 pinentry-curses: no LC_CTYPE known - assuming UTF-8 gpg-agent[1009]: command get_passphrase failed: Invalid IPC response gpg: problem with the agent: Invalid IPC response gpg: decryption failed: No secret key Leiningen can't present enter-passphrase page of gpg. It's an issue with Leiningen or gpg2 or gpg-agent or pinentry. Use the GUI version of gpg, GPG Suite. Now when executing 'lein repl', it prompts for passphrase on the GUI instead. leiningen-2.9.1/doc/MANAGED_DEPS.md000066400000000000000000000142401343535564500164470ustar00rootroot00000000000000 # Managed Dependencies With Leiningen Maven (and now Leiningen) provides a capability called "Dependency Management". The idea is to provide a way to specify a version number for common library dependencies in a single location, and re-use those version numbers from other discrete maven/lein projects. This makes it easy to, e.g., update your `clj-time` dependency across a large number of projects without having to be mindful of every common dependency version across all of your libraries. When using `:pedantic? :abort` in your projects, to ensure that you are producing a consistent and predictable build, it can be very cumbersome to play the "dependency version whack-a-mole" game that arises whenever an upstream library bumps a version of one of its dependencies. `:managed-dependencies` can help alleviate this issue by allowing you to keep the dependency version numbers centralized. ## `:managed-dependencies` The `:managed-dependencies` section of your `project.clj` file is just like the regular `:dependencies` section, with two exceptions: 1. It does not actually introduce any dependencies to your project. It only says, "hey leiningen, if you encounter one of these dependencies later, here are the versions that you should fall back to if the version numbers aren't explicitly specified." 2. It allows the version number to be omitted from the `:dependencies` section, for any artifact that you've listed in your `:managed-dependencies` section. Here's an example: ```clj (defproject superfun/happyslide "1.0.0-SNAPSHOT" :description "A Clojure project with managed dependencies" :min-lein-version "2.7.0" :managed-dependencies [[clj-time "0.12.0"] [me.raynes/fs "1.4.6"] [ring/ring-codec "1.0.1"]] :dependencies [[clj-time] [me.raynes/fs]]) ``` In the example above, the final, resolved project will end up using the specified versions of `clj-time` and `me.raynes/fs`. It will not have an actual dependency on `ring/ring-codec` at all, since that is not mentioned in the "real" `:dependencies` section. This feature is not all that useful on its own, because in the example above, we're specifying the `:managed-dependencies` and `:dependencies` sections right alongside one another, and you could just as easily include the version numbers directly in the `:dependencies` section. The feature becomes more powerful when your build workflow includes some other way of sharing the `:managed-dependencies` section across multiple projects. ## A note on modifiers (`:exclusions`, `:classifier`, etc.) The managed dependencies support in leiningen *does* work with modifiers such as `:exclusions` and `:classifier`. There are two legal syntaxes; you can explicitly specify a `nil` for the version string, or you can simply omit the version string: ```clj (defproject superfun/happyslide "1.0.0-SNAPSHOT" :description "A Clojure project with managed dependencies" :min-lein-version "2.7.0" :managed-dependencies [[clj-time "0.12.0"]] :dependencies [[clj-time :exclusions [foo]]]) ``` or ```clj (defproject superfun/happyslide "1.0.0-SNAPSHOT" :description "A Clojure project with managed dependencies" :min-lein-version "2.7.0" :managed-dependencies [[clj-time "0.12.0"]] :dependencies [[clj-time nil :exclusions [foo]]]) ``` Note that `:classifier` is actually a part of the maven coordinates for an artifact, so for `:classifier` artifacts you will need to specify the `:classifier` value in both the `:managed-dependencies` and the normal `:dependencies` section: ```clj (defproject superfun/happyslide "1.0.0-SNAPSHOT" :description "A Clojure project with managed dependencies" :min-lein-version "2.7.0" :managed-dependencies [[commons-math "1.2" :classifier "sources"]] :dependencies [[commons-math :classifier "sources"]]) ``` ## Lein "parent" projects One way of leveraging `:managed-dependencies` across multiple projects is to use the [`lein-parent` plugin](https://github.com/achin/lein-parent). This plugin will allow you to define a single "parent" project that is inherited by multiple "child" projects; e.g.: ```clj (defproject superfun/myparent "1.0.0" :managed-dependencies [[clj-time "0.12.0"] [me.raynes/fs "1.4.6"] [ring/ring-codec "1.0.1"]]) (defproject superfun/kid-a "1.0.0-SNAPSHOT" :parent-project [:coords [superfun/myparent "1.0.0"] :inherit [:managed-dependencies]] :dependencies [[clj-time] [me.raynes/fs]]) (defproject superfun/kid-b "1.0.0-SNAPSHOT" :parent-project [:coords [superfun/myparent "1.0.0"] :inherit [:managed-dependencies]] :dependencies [[clj-time] [ring/ring-codec]]) ``` In this example, we've consolidated the task of managing common version dependencies in the parent project, and defined two child projects that will inherit those dependency versions from the parent without needing to specify them explicitly. This makes it easier to ensure that all of your projects are using the same versions of your common dependencies, which can help make sure that your uberjar builds are more predictable and repeatable. ## Other ways to share 'managed-dependencies' Since the `defproject` form is a macro, it would be possible to write other plugins that generated the value for a `:managed-dependencies` section dynamically. That could provide other useful ways to take advantage of the `:managed-dependencies` functionality without needing to explicitly populate that section in all of your `project.clj` files. ## Future integration It is likely that the functionality provided by the `lein-parent` plugin may integrated into the leiningen core in a future release; for now we have added only the `:managed-dependencies` functionality because it is necessary in order for the plugin to leverage it. We will be experimenting with different ideas for implementation / API in plugins and making sure that we find an API that works well before submitting for inclusion into core leiningen. leiningen-2.9.1/doc/MIXED_PROJECTS.md000066400000000000000000000155241343535564500167650ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Polyglot (Clojure, Java) Projects With Leiningen](#polyglot-clojure-java-projects-with-leiningen) - [Source Layout](#source-layout) - [Java Source Compilation](#java-source-compilation) - [Setting Java Compiler Options With Leiningen](#setting-java-compiler-options-with-leiningen) - [Interleaving Compilation Steps](#interleaving-compilation-steps) # Polyglot (Clojure, Java) Projects With Leiningen Clojure is a hosted language that encourages interoperability with its platform. It is not uncommon to find some amount of Java code in Clojure projects managed by Leiningen. This guide explains how you can control source code layout with Leiningen, compile Java sources and other topics related to polyglot codebases. ## Source Layout By default, Leiningen assumes your project only has Clojure source code under `src`. When using both Clojure and Java in the same codebase, however, it is necessary to tell Leiningen where to find Java sources. To do so, use `:source-paths` and `:java-source-path` options in the project definition: ```clojure (defproject megacorp/superservice "1.0.0-SNAPSHOT" :description "A Clojure project with a little bit of Java sprinkled here and there" :min-lein-version "2.0.0" :source-paths ["src/clojure"] :java-source-paths ["src/java"]) ``` Having one source root contain another (e.g. `src` and `src/java`) can cause obscure problems. ## Java Source Compilation To compile Java sources, you can explicitly run lein javac However, it is usually not necessary because tasks that need to run project code (`lein test`, `lein run`, etc.) will trigger compilation automatically. Manually running `lein javac` may be necessary when using `lein do`, `lein with-profiles` or `lein repl` actively while also actively changing Java sources in the project. Running lein clean will remove all compilation artifacts. ## Setting Java Compiler Options With Leiningen When compiling Java sources, it may be necessary to pass extra arguments to the compiler. For example, it is very important to target the JVM version you are going to deploy your project to. This is done via the `:javac-options` which takes a vector of arguments as you would pass them to `javac` on the command line. In this case we say that Java sources use features up to JDK 6 and target JVM is also version 6: ```clojure (defproject megacorp/superservice "1.0.0-SNAPSHOT" :description "A Clojure project with a little bit of Java sprinkled here and there" :min-lein-version "2.0.0" :source-paths ["src/clojure"] :java-source-paths ["src/java"] :javac-options ["-target" "1.6" "-source" "1.6"]) ``` Leiningen 2 and later versions uses the [JDK compiler API](https://docs.oracle.com/javase/7/docs/technotes/guides/javac/index.html) to compile Java sources. Failing to specify the target version will lead JDK compiler to target whatever JDK Leiningen is running on. It is a good practice to explicitly specify target JVM version in mixed Clojure/Java projects. ## Interleaving Compilation Steps In some cases it may be necessary to alternate between compiling different languages. For instance, systems that generate and reference Java sources may also provide Clojure code for the generated sources to use. Any Clojure code referenced by Java sources must be [AOT compiled](https://clojure.org/compilation) to make it available to the Java compiler. Similarly, the Java classes produced by `javac` must be available for Clojure code that depends on it. This results in steps of `compile` `javac` `compile`, whereas the default task order is simply `javac` `compile`. This sequence can be accomplished by executing lein with different profiles. A profile can be built to perform the initial steps, while another profile continues to the final compilation stage. For instance, the following is an example of a profile called `:precomp` that AOT compiles the `ex.ast` namespace. The sources for this first step are kept in separate directory from the source directory used by the default profile: ```clojure :profiles { :precomp { :source-paths ["src/pre/clojure"] :aot [ex.ast] } } ``` This profile can then be compiled using: `lein with-profile precomp compile` n Once this is done, the default profile can be used in a separate invocation of `lein` to perform the `javac` and `compile` steps. The following is a complete example of a project that interleaves Clojure and Java compiling. The entire project uses Clojure, except for generated Java sources. In this case, the project uses the Beaver parser generator to create Java source code which calls code written in Clojure. The resulting parser is then referenced by Clojure code. ```clojure (defproject example/parser "0.0.1" :description "Parser written in Clojure, with generated Java sources" :min-lein-version "2.0.0" :dependencies [[org.clojure/clojure "1.5.0"] [net.sf.beaver/beaver-ant "0.9.9"]] :plugins [[lein-beaver "0.1.2-SNAPSHOT"]] :source-paths ["src/clojure"] :java-source-paths ["target/src"] :grammar-src-dir "src/grammar" :grammar-dest-dir "target/src" :profiles { :precomp { :prep-tasks ^:replace ["beaver" "compile"] :source-paths ["src/pre/clojure"] :aot [parser.ast] } }) ``` The `:prep-tasks` attribute in the profile adds the source-code generation step into the sequence of operations to be performed when compiling (though this could have been added to the default profile instead - so long as it occurs before the javac). The `:beaver` task uses `:grammar-src-dir` to find the grammar files and creates the Java sources in the directory specified by `:grammar-dest-dir` (this is placed in "target/" to ensure that it gets removed during a clean). It should be apparent that the generated code is going to use classes and/or protocols found in the `parser.ast` namespace, which is why this namespace is AOT compiled. Also, note that the target of the `beaver` step matches the sources of the default profile for the subsequent `javac` step. Running the `precomp` profile generates the .java sources and compiles the `parser.ast` namespace: ```bash $ lein with-profile precomp compile ``` The project is now ready to complete compilation normally. For instance, invoking `lein test` or `lein uberjar` will cause `javac` and `compile` to run first. ## Other Languages Java is not the only language you can mix with Leiningen, but it's the only one supported out of the box. Plugins exist for [Scala](https://github.com/technomancy/lein-scalac) and [Groovy](https://github.com/kurtharriger/lein-groovyc) as well. leiningen-2.9.1/doc/PLUGINS.md000066400000000000000000000614371343535564500157330ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Leiningen Plugins](#leiningen-plugins) - [Writing a Plugin](#writing-a-plugin) - [Local development](#local-development) - [Task Arguments](#task-arguments) - [Documentation and subtasks](#documentation-and-subtasks) - [Code Evaluation](#code-evaluation) - [Evaluating In Project Context](#evaluating-in-project-context) - [Other Plugin Contents](#other-plugin-contents) - [Profiles](#profiles) - [Hooks](#hooks) - [Project Middleware](#project-middleware) - [Maven Wagons](#maven-wagons) - [VCS Methods](#vcs-methods) - [Requiring Plugins](#requiring-plugins) - [Clojure Version](#clojure-version) - [Upgrading Existing Plugins](#upgrading-existing-plugins) - [Projects vs Standalone Execution](#projects-vs-standalone-execution) - [Overriding Built-in Tasks](#overriding-built-in-tasks) - [1.x Compatibility](#1x-compatibility) - [Project-specific Tasks](#project-specific-tasks) - [Have Fun](#have-fun) [Japanese](ja/PLUGINS_ja.md) # Leiningen Plugins Leiningen tasks are simply functions named `$TASK` in a `leiningen.$TASK` namespace. So writing a Leiningen plugin is just a matter of creating a project that contains such a function, but much of this documentation applies equally to the tasks that ship with Leiningen itself. Using the plugin is a matter of declaring it in the `:plugins` entry of the project map. If a plugin is a matter of user convenience rather than a requirement for running the project, users should place the plugin declaration in the `:user` profile in `~/.lein/profiles.clj` instead of directly in the `project.clj` file. ## Not Writing a Plugin (无为) The first thing to do when writing a plugin is to try to accomplish what you're doing without a plugin. Early on in the days of Leiningen many plugins were written which did nothing but provide a short command to run a specific function using `eval-in-project`. Once Leiningen added the support for partially-applied aliases these became largely redundant, because you can add an alias to the `run` task: :aliases {"mytest" ["run" "-m" "mylib.test/go"]} Not only does this allow `lein mytest` to run the `mylib.test/go` function inside the context of your project, it also passes additional arguments (such as in the case of `lein run mytest :integration`) on to the function specified. However, for some plugins this wasn't enough as they needed access to values in the project map. For instance, a test runner would need to know the value of `:test-paths` to know which directory to scan for tests. As of Leiningen 2.4.0 it's possible to get this data from an alias, removing the need for a plugin. :aliases {"mytest" ["run" "-m" "mylib.test/go" :project/test-paths]} This will load the `:test-paths` value from the project map and pass a string representation of it as the first argument to the function specified in the alias, followed by any command-line arguments given to the `mytest` alias. It's up to the function to call `read-string` on that argument. However, if you need to call other Leiningen functions or have no need to run anything inside the context of the project's own process, making a plugin might be the right choice if one doesn't [exist already](https://github.com/technomancy/leiningen/wiki/plugins), ## Writing a Plugin Start by generating a new project with `lein new plugin myplugin`, and edit the `myplugin` defn in the `leiningen.myplugin` namespace. You'll notice the `project.clj` file has `:eval-in-leiningen true`, which causes all tasks to operate inside the leiningen process rather than starting a subprocess to isolate the project's code. Plugins need not declare a dependency on Clojure itself; in fact [all of Leiningen's own dependencies](https://github.com/technomancy/leiningen/blob/stable/project.clj) will be available. See the `lein-pprint` directory [in the Leiningen source](https://github.com/technomancy/leiningen/tree/stable/lein-pprint) for a sample of a very simple plugin. When emitting output, please use `leiningen.core.main/info`, `leiningen.core.main/warn`, and `leiningen.core.main/debug` rather than `println` since these will respect the user's output settings. ### Local development When you're ready to test your plugin in a separate project you can include it via the following (example a plugin named sample-plugin): ``` lein install Created ~/sample-plugin/target/sample-plugin-0.1.0-SNAPSHOT.jar Wrote ~/sample-plugin/pom.xml Installed jar and pom into local repo. ``` This will build a jar using the :version listed in the plugin's project.clj file (see above for example project.clj) and install it into your local m2 repository (~/.m2/repository) After this step completes you can now list your plugin in your separate project with the version outputted from above. This example would look like this: ``` ... :plugins [[sample-plugin "0.1.0-SNAPSHOT"]] ... ``` During local development, having to re-run `lein install` in your plugin project and then switch to a test project can be very cumbersome. In order to avoid this annoyance, you can do the following: 1. If you haven't done it yet, run `lein install` in the plugin's project directory. 2. Just to make sure, run `lein help ` in your test project directory. A help message for your plugin should be displayed now. Or an exception originating in your plugin. 3. Add the path to the `src` directory of your plugin to the file `.lein-classpath` in your test project directory. Probably you'll have to create that file. 4. If your plugin depends on another library that you are also working on, then that needs to be added to `.lein-classpath` with the classpath separator, either `:` for unix, or `;` for Windows. The same goes for your plugin's other direct dependencies. Run `lein classpath` in order to get an idea how the contents of `.lein-classpath` are supposed to look. 5. Remove the entry for your plugin from the test project's `project.clj`. Otherwise it would override what you've added to `.lein-classpath`, because Leiningen loads those things before it loads plugins. ### Task Arguments The first argument to your task function should be the current project. It will be a map which is based on the `project.clj` file, but it also has `:name`, `:group`, `:version`, and `:root` keys added in, among other things. Try using the `lein-pprint` plugin to see what project maps look like; you can invoke the `pprint` task to examine any project or combination of profiles. If you want your task to take parameters from the command-line invocation, you can make the function take more than one argument. In order to underscore the fact that tasks are just Clojure functions, arguments which act as flags are usually accepted as `:keywords` rather than unixy traditional `--dashed` syntax. Note that all arguments are still passed in as strings; it's up to your function to call `read-string` on the arguments if you want keywords, symbols, integers, etc. Keep this in mind when calling other tasks as functions too. Most tasks may only be run in the context of a project. If your task can be run outside a project directory, add `^:no-project-needed` as metadata to your task defn to indicate so. Your task must still accept a project as its first argument, but it will be allowed to be nil. Leiningen will still pass you the project as first argument if lein is called from within a project. If called outside of a project, lein will send in profile information from `$HOME/.lein/profiles.clj` and similar sources as a map similar to a project map. Other tools using the `leiningen-core` library (IDE integration, etc) may decide to just pass in nil. To distinguish between a project and non-project, check for the `:root` key. If it's set, then you are in a project, otherwise you are not. ### Documentation and subtasks The `lein help` task uses docstrings. A namespace-level docstring will be used as the short summary if present; if not then it will take the first line of your function's docstring. Try to keep the summary under 68 characters for formatting purposes. The full docstring can of course be much longer but should still be wrapped at 80 columns. The function's arglists will also be shown, so pick argument names that are clear and descriptive. If you set `:help-arglists` in the function's metadata, it will be used instead for those cases where alternate arities exist that aren't intended to be exposed to the user. Be sure to explain all these arguments in the docstring. Note that all your arguments will be strings, so it's up to you to call `read-string` on them if you want keywords, numbers, or symbols. Often more complicated tasks get divided up into subtasks. Placing `:subtasks` metadata on a task defn which contains a vector of subtask vars will allow `lein help $TASK_CONTAINING_SUBTASKS` to list them. This list of subtasks will show the first line of the docstring for each subtask. The full help for a subtask can be viewed via `lein help $TASK_CONTAINING_SUBTASKS $SUBTASK`. Note that Leiningen doesn't have a mechanism for automatically invoking subtasks. You'll have to do that yourself in the main task. A dumb implementation of it all might look like this: ```clojure (defn my-task "Automatically write all the project's code." {:subtasks [#'my-subtask-0 #'my-subtask-1]} [project & [sub-name]] (case sub-name "my-subtask-0" (my-subtask-0 project args) "my-subtask-1" (my-subtask-1 project args) nil :not-implemented-yet (leiningen.core.main/warn "Unknown task."))) ``` Leiningen will intercept calls to `lein $MYTASK help` by default and turn them into `lein help $MYTASK`. If your task provides its own help subtask you can add `^:pass-through-help` metadata to your task defn to opt-out of this behaviour. ## Code Evaluation Plugin functions run inside Leiningen's process, so they have access to all the existing Leiningen functions. The public API of Leiningen should be considered all public functions inside the `leiningen.core.*` namespaces not labeled with `^:internal` metadata as well as each individual task functions. Other non-task functions in task namespaces should be considered internal and may change inside point releases. ### Evaluating In Project Context Many tasks need to execute code inside the context of the project itself. The `leiningen.core.eval/eval-in-project` function is used for this purpose. It accepts a project argument as well as a form to evaluate, and the final (optional) argument is another form called `init` that is evaluated up-front before the main form. This may be used to require a namespace earlier in order to avoid the [Gilardi Scenario](https://technomancy.us/143). Inside the `eval-in-project` call the project's own classpath will be active and Leiningen's own internals and plugins will not be available. You can modify the project map before you pass it into `eval-in-project`. However, it's recommended that you make your modifications by merging a profile in so users can override your changes if necessary. Use `leiningen.core.project/merge-profiles` to make your changes: ```clj (def swank-profile {:dependencies [['swank-clojure "1.4.3"]]}) (defn swank "Launch swank server for Emacs to connect. Optionally takes PORT and HOST." [project port host & opts] (let [profile (or (:swank (:profiles project)) swank-profile) project (project/merge-profiles project [profile])] (eval-in-project project `(swank.core/-main ~@opts) '(require 'swank.core)))) ``` The code in the `swank-clojure` dependency is needed inside the project, so it's declared in its own profile map and merged in. However, we defer to the `:swank` profile in the project map if it's present so that the user can pick their own version of the dependency if they like rather than relying on the hard-coded profile in the plugin. Note that the snippet above is not a good example of a plugin since it simply wraps `eval-in-project` and `merge-profiles`. If that is all you want, you can do it without implementing a plugin; just define an alias that uses the `with-profiles` and `run` tasks to call the function you need. Before `eval-in-project` is invoked, Leiningen must "prep" a project, usually by ensuring that all Java code and all necessary Clojure code has been AOT compiled to bytecode. This is done by running all the tasks in the `:prep-tasks` key of the project, which defaults to `["javac" "compile"]`. If your plugin requires another kind of prepping, (for instance, compiling protocol buffers) you can instruct users to add another entry to `:prep-tasks`. Note that this task will be invoked for **every** `eval-in-project`, so take care that it runs quickly if nothing has changed since the last run. ## Other Plugin Contents Plugins are primarily about providing tasks, but they can also contain profiles, hooks, middleware, wagons (dependency transport methods), and vcs methods. ### Profiles If there is configuration that is likely to be used by many projects using your plugin, yet for some reason you can't make that configuration active by default, you can include profiles inside your plugin. Create a file called `resources/myplugin/profiles.clj` in your plugin that contains a map: ```clj {:default {:x "y and z"} :extra {:other "settings"}} ``` Each value here is a profile that your users can merge into their project. You can do this explicitly on a per-invocation basis using `with-profile`: $ lein with-profile plugin.myplugin/extra test Users can also have profiles activated automatically by changing the `:default` profile: ```clj :profiles {:default [:base :system :user :provided :dev :plugin.myplugin/default] :other {...}} ``` Everything in the `:default` profile is active for all non-`with-profile` task invocations except for those which produce downstream artifacts, like `jar`, `uberjar`, and `pom`. ### Hooks **Note**: Leiningen supports loading hooks from plugins; however this mechanism is extremely error-prone and difficult to debug. It should be considered deprecated as of 2.8.0 onward and will continue to work until version 3.0 but is strongly advised against. You can modify the behaviour of built-in Leiningen tasks to a degree using hooks. Hook functionality is provided by the [Robert Hooke](https://github.com/technomancy/robert-hooke) library, which is included with Leiningen. Inspired by clojure.test's fixtures functionality, hooks are functions which wrap other functions (often tasks) and may alter their behaviour by binding other vars, altering the return value, only running the function conditionally, etc. The `add-hook` function takes a var of the task it's meant to apply to and a function to perform the wrapping: ```clj (ns lein-integration.plugin (:require [robert.hooke] [leiningen.test])) (defn add-test-var-println [f & args] `(binding [~'clojure.test/assert-expr (fn [msg# form#] (println "Asserting" form#) ((.getRawRoot #'clojure.test/assert-expr) msg# form#))] ~(apply f args))) ;; Place the body of the activate function at the top-level for ;; compatibility with Leiningen 1.x (defn activate [] (robert.hooke/add-hook #'leiningen.test/form-for-testing-namespaces #'add-test-var-println)) ``` Hooks compose, so be aware that your hook may be running inside another hook. See [the documentation for Hooke](https://github.com/technomancy/robert-hooke/blob/master/README.md) for more details. Note that calls to `add-hook` should use the var for both the first and second argument so that hooks can be loaded repeatedly without re-adding the hook. This is because in Clojure bare functions cannot be compared for equality, but vars can. If you want your hooks to be loaded automatically when other projects include your plugin, activate them in a function called `plugin-name.plugin/hooks`. So in the example above the plugin is called `lein-integration`, and the function `lein-integration.plugin/hooks` is automatically called to activate hooks when the `lein-integration` plugin is loaded. Hooks can also be loaded manually by setting the `:hooks` key in project.clj to a seq of vars to call to activate your hooks. For backward compatibility, you can also specify namespaces instead of vars in `:hooks`, and the `activate` function in that namespace will be called. Note: automatic hooks are activated before manually specified hooks. ### Project Middleware Project middleware is just a function that is called on a project map returning a new project map. Middleware gives a plugin the power to do any kind of transformation on the project map. However, problems with middleware can be difficult to debug due to their flexibility and opaqueness. If you can do what you need using profiles inside your plugins instead, that is a much more declarative, introspectable way to do things which will save a lot of headache down the line. The following middleware injects additional javac options into the project map, but only if there are any java source paths in the project: ```clj (ns leiningen.inject (:require [leiningen.core.project :as p])) (def javac-params-profile {:javac-options ^:prepend ["-target" "1.6" "-source" "1.6"]}) (defn middleware [project] (if (seq (:java-source-paths project)) (p/merge-profiles project [javac-params-profile]) project)) ``` Projects use middleware by adding `:middleware` as a vector of var names into their `project.clj`: ```clj :middleware [leiningen.inject/middleware] ``` Also note that the currently active middleware depends on which profiles are active. This means we need to reapply the middleware functions to the project map whenever the active profiles change. We accomplish this by storing the fresh project map and starting from that whenever we call `merge-profiles`, `unmerge-profiles` or `set-profiles`. It also means your middleware functions shouldn't have any non-idempotent side-effects since they could be called repeatedly. If you need to include a profile in the project map, please add it as a plugin profile and ask your users to add it to the `:base` profile as outlined in the "Plugin" subsection of "Other Plugin Contents" in this document. This makes the "injection" more explicit and easier to debug. The only times one should use middleware to inject values into the project map is if the profiles has to be programmatically computed, or if you have to modify the project map in a way that is not possible with `merge-profiles`. **Note**: Leiningen supports loading middleware implicitly when the middleware is named `plugin-name.plugin/middleware`; however this mechanism is even more difficult to debug than regular middleware. It should be considered deprecated as of 2.8.0 onward and will continue to work until version 3.0 but is strongly advised against. ### Maven Wagons [Pomegranate](https://github.com/cemerick/pomegranate) (the library used by Leiningen to resolve dependencies) supports registering "wagon" factories. Wagons are used to handle non-standard transport protocols for repositories, and are looked up based on the protocol of the repository url. If your plugin needs to register a wagon factory, it can do so by providing a `leiningen/wagons.clj` file containing a map of protocols to functions that return wagon instances for the protocol. For example, the following `wagons.clj` will register a wagon factory function for `dav:` urls: ```clj {"dav" #(org.apache.maven.wagon.providers.webdav.WebDavWagon.)} ``` See [S3 wagon private](https://github.com/technomancy/s3-wagon-private) or [lein-webdav](https://github.com/tobias/lein-webdav) for full examples of plugins using this technique. ### VCS Methods Leiningen ships with a `vcs` task which performs a handful of release-related version control tasks via multimethods. Out of the box it contains implementations for Git, but plugins can add support for more systems by including a `leiningen.vcs.$SYSTEM` namespace. All namespaces under the `leiningen.vcs.` prefix will be loaded when the `vcs` task is invoked. These namespaces should simply define methods for the `defmulti`s in `leiningen.vcs` that invoke the specific version control system. ## Requiring Plugins To use a plugin in your project, just add a `:plugins` key to your project.clj with the same format as `:dependencies`. In addition to the options allowed by `:dependencies`, `:plugins` also allows you to disable auto-loading of hooks or middleware. ```clj (defproject foo "0.1.0" :plugins [[lein-pprint "1.1.1"] [lein-foo "0.0.1" :hooks false] [lein-bar "0.0.1" :middleware false]]) ``` ## Clojure Version Leiningen 2.7.0 and on uses Clojure 1.8.0. If you need to use a different version of Clojure from within a Leiningen plugin, you can use `eval-in-project` with a dummy project argument: ```clj (eval-in-project {:dependencies '[[org.clojure/clojure "1.4.0"]]} '(println "hello from" *clojure-version*)) ``` ## Projects vs Standalone Execution Some Leiningen tasks can be executed from any directory (e.g. `lein repl`). Some only make sense in the context of a project. To check whether Leiningen is running in the context of a project (that is, if a `project.clj` is present in the current directory), check for the `:root` key in the project map: ``` clojure (if (:root project) (comment "Running in a project directory") (comment "Running standalone")) ``` If your plugin may run outside the context of the project entirely, you should still leave room in the arguments list for a project map; just expect that it will be nil if there's no project present. Use `^:no-project-needed` metadata to indicate this is acceptable. In Leiningen 1.x, having a task function return a numeric value was a way to signal the process's exit code. In Leiningen 2.x, tasks should call the `leiningen.core.main/abort` function when a fatal error is encountered. If the `leiningen.core.main/*exit-process?*` var is bound to true, then this will trigger an exit, but in some contexts (like `with-profiles`) it will simply trigger an exception and go on to the next task. ## Overriding Built-in Tasks Normally if you create a plugin containing (say) a `leiningen.compile` namespace, it won't be used when `lein compile` is run; the built-in task will override it. If you'd like to shadow a built-in task, you can either create an alias or put it in the `leiningen.plugin.compile` namespace. ## Project-specific Tasks Occasionally, the need arises for a task to be included in a project's codebase. However, this is much less common than people think. If you simply have some code that needs to be invoked from the command-line it's much simpler to have your code run in a `-main` function inside your project and invoke it with an alias like `lein garble`: ```clj :aliases {"garble" ["run" "-m" "myproject.garble" "supergarble"]} ``` Note that aliases vectors result in partially applied task functions, so with the above config, `lein garble seventeen` would be equivalent to `lein run -m myproject.garble supergarble seventeen` (or `(myproject.garble/-main "supergarble" "seventeen")` from the repl). The arguments in the alias are concatenated to the arguments provided when it's invoked. You only need to write a Leiningen task if you need to operate outside the context of your project, for instance if you need to adjust the project map before calling `eval-in-project` or some other task where you need direct access to Leiningen internals. You can even read values from the project map with an alias: ```clj :aliases {"garble" ["run" "-m" "myproject.garble" :project/version]} ``` This will splice the value of the project map's `:version` field into the argument list so that the `-main` function running inside the project code gets access to it. The vast majority of these cases are already covered by [existing plugins](https://github.com/technomancy/leiningen/wiki/plugins), but if you have a case that doesn't exist and for some reason can't spin it off into its own separate plugin, you can enable this behavior by placing the `foo.clj` file defining the new task in `tasks/leiningen/` and add `tasks` to your `.lein-classpath`: ``` $ ls README.md project.clj src tasks test $ ls -R tasks leiningen tasks/leiningen: foo.clj $ echo -ne ":tasks" | cat >> .lein-classpath $ lein foo Hello, Foo! ``` Note that in most cases it's better to spin off tasks into their own plugin projects; using `.lein-classpath` is mainly appropriate for experimentation or cases when there isn't enough time to create a proper plugin. ## Have Fun Please add your plugin to [the list on the wiki](https://github.com/technomancy/leiningen/wiki/plugins) once it's ready. Hopefully the plugin mechanism is simple and flexible enough to let you bend Leiningen to your will. leiningen-2.9.1/doc/PROFILES.md000066400000000000000000000257101343535564500160270ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Profiles](#profiles) - [Declaring Profiles](#declaring-profiles) - [Default Profiles](#default-profiles) - [Task Specific Profiles](#task-specific-profiles) - [Profile Metadata](#profile-metadata) - [Merging](#merging) - [Activating Profiles](#activating-profiles) - [Composite Profiles](#composite-profiles) - [Dynamic Eval](#dynamic-eval) - [Debugging](#debugging) # Profiles You can change the configuration of your project by applying various profiles. For instance, you may want to have a few extra test data directories on the classpath during development without including them in the jar, or you may want to have development tools like [Slamhound](https://github.com/technomancy/slamhound) available in every project you hack on without modifying every single `project.clj` you use. You can place any arbitrary key/value pairs supported by `defproject` into a given profile and they will be merged into the project map when that profile is activated. The example below adds a "dummy-data" resources directory during development and a dependency upon "expectations" that's only used for tests/development. ```clj (defproject myproject "0.5.0-SNAPSHOT" :description "A project for doing things." :dependencies [[org.clojure/clojure "1.4.0"]] :profiles {:dev {:resource-paths ["dummy-data"] :dependencies [[expectations "1.4.41"]]}}) ``` Use the `show-profiles` task to list the project's profiles. ## Declaring Profiles In addition to `project.clj`, profiles also can be specified in `profiles.clj` within the project root. Profiles specified in `profiles.clj` will override profiles in `project.clj` (via [merging](#merging) logic described below), so this can be used for project-specific overrides that you don't want committed in version control. User-wide profiles can also be specified in `~/.lein/profiles.clj`. These will be available in all projects managed by Leiningen, though those profiles will be overridden by profiles of the same name specified in the project. System-wide profiles can be placed in `/etc/leiningen/profiles.clj`. They are treated the same as user profiles, but with lower precedence. You can also define user-wide profiles within `clj`-files inside `~/.lein/profiles.d`. The semantics within such files differ slightly from other profile files: rather than a map of maps, the profile map is the top-level within the file, and the name of the profile comes from the file itself (without the `.clj` part). Defining the same user-wide profile in both `~/.lein/profiles.clj` and in `~/.lein/profiles.d` is considered an error. ## Default Profiles Certain profiles are active by default unless you specify another set of profiles using the `with-profile` task. Each of the default profiles have different semantics: If you want to access dependencies or plugins during development time for any project place them in your `:user` profile. Your `~/.lein/profiles.clj` file could look something like this: ```clj {:user {:plugins [[lein-pprint "1.1.1"]] :dependencies [[slamhound "1.3.1"]]}} ``` The `:dev` profile is used to specify project specific development tooling. Put things here if they are required for builds or tests, rather than just convenience tooling. The `:user` profile is separate from `:dev`; the latter is intended to be specified in the project itself. In order to avoid collisions, the project should never define a `:user` profile, nor should a user-wide `:dev` profile be defined. Likewise, system profiles should use the `:system` profile, and define neither `:user` nor `:dev` profiles. The `:system` profile is similar to `:user`, except it applies system-wide instead of merely to a single user. The `:base` profile provides dependencies necessary for basic repl functionality, adds `dev-resources` to the `:resource-paths`, and sets defaults for `:jvm-opts`, `:checkout-deps-share` and `:test-selectors`. It is part of Leiningen itself; you shouldn't need to change it. The profiles listed above are active during development, but they are unmerged before the jar and pom files are created, making them invisible to code that depends upon your project. The `:provided` profile is used to specify dependencies that should be available during jar creation, but not propagated to other code that depends on your project. These are dependencies that the project assumes will be provided by whatever environment the jar is used in, but are needed during the development of the project. This is often used for frameworks like Hadoop that provide their own copies of certain libraries. The `:default` profile specifies the profiles that are active by default when running lein tasks. If not overridden, this is set to `:leiningen/default`, which is a composite profile with `[:base :system :user :provided :dev]`. ## Task Specific Profiles Some tasks automatically merge a profile if specified. Examples of these are the `:test` profile, when running the `test` task, and the `:repl` profile, when running the `repl` task. Please note that putting things in the `:test` profile is strongly advised against as it can result in tests which can't be run from the repl. ## Profile Metadata If you mark your profile with `^:leaky` metadata, then the profile will not be stripped out when the pom and jar files are created. If you mark a profile with `^{:pom-scope :test}` metadata, then the profile's `:dependencies` will be added with a `test` scope in the generated pom and jar when active. The `:dev`, `:test`, and `:base` profiles have this set automatically. If you mark a profile with `^{:pom-scope :provided}` metadata, then the profile's `:dependencies` will be added with a `provided` scope in the generated pom and jar when active. The `:provided` profile has this set automatically. ## Merging Profiles are merged by taking each key in the project map or profile map, combining the value if it's a collection and replacing it if it's not. Profiles specified later take precedence when replacing, just like the `clojure.core/merge` function. The dev profile takes precedence over user by default. Maps are merged recursively, sets are combined with `clojure.set/union`, and lists/vectors are concatenated. You can add hints via metadata that a given value should take precedence (`:replace`) or defer to values from a different profile (`:displace`) if you want to override this logic: ```clj {:profiles {:dev {:prep-tasks ^:replace ["clean" "compile"] :aliases ^:displace {"launch" "run"}}}} ``` The exception to this merge logic is that `:plugins` and `:dependencies` have custom de-duplication logic since they must be specified as vectors even though they behave like maps (because it only makes sense to have a single version of a given dependency present at once). The replace/displace metadata hints still apply though. Remember that if a profile with the same name is specified in multiple locations, only the profile with the highest "priority" is picked – no merging is done. The "priority" is – from highest to lowest – `profiles.clj`, `project.clj`, user-wide profiles, and finally system-wide profiles. If you need to enable personal overrides of parts of a profile, you can use a composite profile with common and personal parts - something like `:dev [:dev-common :dev-overrides]`; you would then have just `:dev-overrides {}` in `project.clj` and override it in `profiles.clj`. Another use of profiles is to test against various sets of dependencies: ```clj (defproject swank-clojure "1.5.0-SNAPSHOT" :description "Swank server connecting Clojure to Emacs SLIME" :dependencies [[org.clojure/clojure "1.2.1"] [clj-stacktrace "0.2.4"] [cdt "1.2.6.2"]] :profiles {:1.3 {:dependencies [[org.clojure/clojure "1.3.0"]]} :1.4 {:dependencies [[org.clojure/clojure "1.4.0-beta1"]]}}) ``` ## Activating Profiles To activate a different set of profiles for a given task, use the `with-profile` higher-order task: $ lein with-profile 1.3 test :database Multiple profiles may be combined with commas: $ lein with-profile qa,user test :database Multiple profiles may be executed in series with colons: $ lein with-profile 1.3:1.4 test :database The above invocations activate the given profiles in place of the defaults. To activate a profile in addition to the defaults, prepend it with a `+`: $ lein with-profile +server run You can also use `-` to deactivate a profile. By default all profiles will share the same `:target-path`, which can cause problems if settings from one profile leak over into another. It's recommended to set `:target-path` to `"target/%s"`, which will isolate each profile set and prevent anything from bleeding over. ## Composite Profiles Sometimes it is useful to define a profile as a combination of other profiles. To do this, just use a vector instead of a map as the profile value. This can be used to avoid duplication: ```clj {:shared {:port 9229, :protocol "https"} :qa [:shared {:servers ["qa.mycorp.com"]}] :stage [:shared {:servers ["stage.mycorp.com"]}] :production [:shared {:servers ["prod1.mycorp.com", "prod1.mycorp.com"]}]} ``` ## Dynamic Eval Often you want to read an environment variable or execute a function to capture a value to use in your profiles. In order to do such a thing with the profiles.clj you'll need to use the read-eval syntax. Here is an example of such a case: ```clj {:user {:compile-path #=(eval (System/getenv "ci.compile-path")), :target-path #=(eval (System/getenv "ci.target-path"))}} ``` ## Debugging To see how a given profile affects your project map, use the [lein-pprint](https://github.com/technomancy/leiningen/tree/stable/lein-pprint) plugin: $ lein with-profile 1.4 pprint {:compile-path "/home/phil/src/leiningen/lein-pprint/classes", :group "lein-pprint", :source-path ("/home/phil/src/leiningen/lein-pprint/src"), :dependencies ([org.clojure/tools.nrepl "0.0.5" :exclusions [org.clojure/clojure]] [clojure-complete "0.1.4" :exclusions [org.clojure/clojure]] [org.thnetos/cd-client "0.3.3" :exclusions [org.clojure/clojure]]), :target-path "/home/phil/src/leiningen/lein-pprint/target", :name "lein-pprint", [...] :description "Pretty-print a representation of the project map."} In order to prevent profile settings from being propagated to other projects that depend upon yours, the `:default` profiles are removed from your project when generating the pom, jar, and uberjar, and an `:uberjar` profile, if present, is included when creating uberjars. (This can be useful if you want to specify a `:main` namespace for uberjar use without triggering AOT during regular development.) Profiles activated through an explicit `with-profile` invocation will be preserved. leiningen-2.9.1/doc/TEMPLATES.md000066400000000000000000000137271343535564500161470ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Writing Templates](#writing-templates) - [Structure](#structure) - [Templating System](#templating-system) - [A warning about Mustache tag delimiters](#a-warning-about-mustache-tag-delimiters) - [Distributing your Template](#distributing-your-template) # Writing Templates Suppose you've written a fabulously popular library, used the world over by adoring fans. For the purposes of this document, let's say this library is called "liquid-cool". If using liquid-cool takes a bit of setup, or if you'd just like to give your users a little guidance on how one might best create a new project which uses liquid-cool, you might want to provide a template for it (just like how `lein` already provides built-in templates for "app", "plugin", and so on). Let's assume your library's project dir is `~/dev/liquid-cool`. Create a template for it like so: cd ~/dev lein new template liquid-cool --to-dir liquid-cool-template Your new template would look like: liquid-cool-template ├── LICENSE ├── project.clj ├── README.md ├── resources | └── leiningen | └── new | └── liquid_cool |    └── foo.clj └── src └── leiningen └── new └── liquid_cool.clj Note that you'll now have a new and separate project named "liquid-cool-template". It will have a group-id of "liquid-cool", and an artifact-id of "lein-template". > All lein templates have an artifact-id of "lein-template", and are > differentiated by their group-id, which always should match the > project for which they provide a template. ## Structure The files that your template will provide to users are in `resources/leiningen/new/liquid_cool`. The template generator starts you off with just one, named "foo.clj". You can see it referenced in `src/leiningen/new/liquid_cool.clj`, right underneath the `->files data` line. You can delete `foo.clj` if you like (and its corresponding line in `liquid_cool.clj`), and start populating that `resources/leiningen/new/liquid_cool` directory with the files you wish to be part of your template. For everything you add, make sure the `liquid_cool.clj` file receives corresponding entries in that `->files` call. For examples to follow, have a look inside [the \*.clj files for the built-in templates](https://github.com/technomancy/leiningen/tree/stable/resources/leiningen/new). ## Testing Your Template While developing a template, if you're in the template project directory, leiningen will pick it up and you'll be able to test it. e.g. from the `liquid-cool-template` dir: $ lein new liquid-cool myproject will create a directory called `myproject`, built from your template. Alternately, if you want to test your template from another directory on your system (without publishing your template to clojars yet), just run: $ lein install You should then be able to run `lein new liquid-cool myproject` from any directory on your system. ## Templating System The default generated template uses [stencil][] for templating, which implements the language-agnostic templating system [Mustache][]. All the available tag types can be found in the [Mustache manual][mustache-manual]; we will only go through the most common tag type here. Suppose we want to add in a standard markdown readme file where the input name is the main header of the file. To be able to do so, we must do two things: Ensure that the input name is contained within the `data` mapped to the key X, and that we have a template file which looks up the key X by wrapping it in double mustaches like so: `{{X}}`. As for our input name, `data` already contains the line `:name name`, which means we can lookup the input name by writing `{{name}}` in the template file. To try it out, save the following contents in the file `resources/leiningen/new/liquid_cool/README.md`: ```markdown # {{name}} This is our readme! ``` And add the following line right underneath the `->files data` line: ```clj ["README.md" (render "README.md" data)] ``` Now, if we for instance say `lein new liquid-cool liquid-cool-app`, the newly generated project will contain a file named `README.md` where the header is `liquid-cool-app`. [stencil]: https://github.com/davidsantiago/stencil [Mustache]: https://mustache.github.io/ [mustache-manual]: https://mustache.github.io/mustache.5.html #### A warning about Mustache tag delimiters Clojure syntax can conflict with the default mustache tag delimiter. For example, when destructuring a nested map: ```clj (let [{{:keys [a b]} :ab} some-map] (do-something a b)) ``` Stencil will interpret the `{{` as the start of a mustache tag, but since the contents are not valid mustache, the render fails. To get around this, we can change the mustache delimiter temporarily, like so: ```clj {{! Change mustache delimiter to <% and %> }} {{=<% %>=}} (let [{{:keys [a b]} :ab} some-map] (do-something a b)) <%! Reset mustache delimiter %> <%={{ }}=%> ``` ## Distributing your Template Templates are just maven artifacts. Particularly, they need only be on the classpath when `lein new` is called. So, as a side-effect, you can just put your templates in a jar and toss them on clojars and have people install them like normal Leiningen plugins. In Leiningen 2.x, templates get dynamically fetched if they're not found. So for instance `lein new heroku myproject` will find the latest version of the `heroku/lein-template` project from Clojars and use that. Users of Leiningen 1.x (1.6.2 or later) can also use the template if they install the `lein-newnew` plugin: $ lein plugin install lein-newnew 0.3.6 $ lein new foo $ lein new plugin lein-foo leiningen-2.9.1/doc/TUTORIAL.md000066400000000000000000000714421343535564500160520ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Tutorial](#tutorial) - [What This Tutorial Covers](#what-this-tutorial-covers) - [Getting Help](#getting-help) - [Leiningen Projects](#leiningen-projects) - [Creating a Project](#creating-a-project) - [Directory Layout](#directory-layout) - [Filename-to-Namespace Mapping Convention](#filename-to-namespace-mapping-convention) - [project.clj](#projectclj) - [Dependencies](#dependencies) - [Overview](#overview) - [Artifact IDs, Groups, and Versions](#artifact-ids-groups-and-versions) - [Snapshot Versions](#snapshot-versions) - [Repositories](#repositories) - [Checkout Dependencies](#checkout-dependencies) - [Search](#search) - [Setting JVM Options](#setting-jvm-options) - [Running Code](#running-code) - [Tests](#tests) - [Profiles](#profiles) - [What to do with it](#what-to-do-with-it) - [Uberjar](#uberjar) - [Framework (Uber)jars](#framework-uberjars) - [Server-side Projects](#server-side-projects) - [Publishing Libraries](#publishing-libraries) - [That's It!](#thats-it) # Tutorial Leiningen is for automating Clojure projects without setting your hair on fire. If you experience your hair catching on fire or any other frustrations while following this tutorial, please [let us know](https://github.com/technomancy/leiningen/issues/new). It offers various project-related tasks and can: * create new projects * fetch dependencies for your project * run tests * run a fully-configured REPL * compile Java sources (if any) * run the project (if the project isn't a library) * generate a maven-style "pom" file for the project for interop * compile and package projects for deployment * publish libraries to repositories such as [Clojars](https://clojars.org) * run custom automation tasks written in Clojure (leiningen plug-ins) If you come from the Java world, Leiningen could be thought of as "Maven meets Ant without the pain". For Ruby and Python folks, Leiningen combines RubyGems/Bundler/Rake and pip/Fabric in a single tool. ## What This Tutorial Covers This tutorial will briefly cover project structure, dependency management, running tests, the REPL, and topics related to deployment. For those of you new to the JVM who have never touched Ant or Maven in anger: don't panic. Leiningen is designed with you in mind. This tutorial will help you get started and explain Leiningen's take on project automation and JVM-land dependency management. ## Getting Help Also keep in mind that Leiningen ships with fairly comprehensive help; `lein help` gives a list of tasks while `lein help $TASK` provides details. Further documentation such as the readme, sample configuration, and even this tutorial are also provided. ## Leiningen Projects Leiningen works with *projects*. A project is a directory containing a group of Clojure (and possibly Java) source files, along with a bit of metadata about them. The metadata is stored in a file named `project.clj` in the project's root directory, which is how you tell Leiningen about things like * Project name * Project description * What libraries the project depends on * What Clojure version to use * Where to find source files * What's the main namespace of the app and more. Most Leiningen tasks only make sense in the context of a project. Some (for example, `repl` or `help`) can also be called from any directory. Next let's take a look at how projects are created. ## Creating a Project We'll assume you've got Leiningen installed as per the [README](https://github.com/technomancy/leiningen/blob/stable/README.md). Generating a new project is easy: $ lein new app my-stuff Generating a project called my-stuff based on the 'app' template. $ cd my-stuff $ find . . ./.gitignore ./doc ./doc/intro.md ./LICENSE ./project.clj ./README.md ./resources ./src ./src/my_stuff ./src/my_stuff/core.clj ./test ./test/my_stuff ./test/my_stuff/core_test.clj In this example we're using the `app` template, which is intended for an application project rather than a library. Omitting the `app` argument will use the `default` template, which is suitable for libraries. ### Directory Layout Here we've got your project's README, a `src/` directory containing the code, a `test/` directory, and a `project.clj` file which describes your project to Leiningen. The `src/my_stuff/core.clj` file corresponds to the `my-stuff.core` namespace. ### Filename-to-Namespace Mapping Convention Note that we use `my-stuff.core` instead of just `my-stuff` since single-segment namespaces are discouraged in Clojure. Also note that namespaces with dashes in the name will have the corresponding file named with underscores instead since the JVM has trouble loading files with dashes in the name. The intricacies of namespaces are a common source of confusion for newcomers, and while they are mostly outside the scope of this tutorial you can [read up on them elsewhere](https://8thlight.com/blog/colin-jones/2010/12/05/clojure-libs-and-namespaces-require-use-import-and-ns.html). ## project.clj Your `project.clj` file will start off looking something like this: ```clj (defproject my-stuff "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "https://example.com/FIXME" :license {:name "Eclipse Public License" :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]] :main ^:skip-aot my-stuff.core :target-path "target/%s" :profiles {:uberjar {:aot :all}}) ``` If you don't fill in the `:description` with a short sentence, your project will be harder to find in search results, so start there. Be sure to fix the `:url` as well. At some point you'll need to flesh out the `README.md` file too, but for now let's skip ahead to setting `:dependencies`. Note that Clojure is just another dependency here. Unlike most languages, it's easy to swap out any version of Clojure. ## Dependencies ### Overview Clojure is a hosted language and Clojure libraries are distributed the same way as in other JVM languages: as jar files. Jar files are basically just `.zip` files with a little extra JVM-specific metadata. They usually contain `.class` files (JVM bytecode) and `.clj` source files, but they can also contain other things like config files, JavaScript files or text files with static data. Published JVM libraries have *identifiers* (artifact group, artifact id) and *versions*. ### Artifact IDs, Groups, and Versions You can [search Clojars](https://clojars.org/search?q=clj-http) using its web interface or via `lein search $TERM`. On the Clojars page for `clj-http` at the time of this writing it shows this: ```clj [clj-http "2.0.0"] ``` It also shows the Maven and Gradle syntax for dependencies. You can copy the Leiningen version directly into the `:dependencies` vector in `project.clj`. So for instance, if you change the `:dependencies` line in the example `project.clj` above to ```clj :dependencies [[org.clojure/clojure "1.8.0"] [clj-http "2.0.0"]] ``` Leiningen will automatically download the `clj-http` jar and make sure it is on your classpath. If you want to explicitly tell lein to download new dependencies, you can do so with `lein deps`, but it will happen on-demand if you don't. Within the vector, "clj-http" is referred to as the "artifact id". "2.0.0" is the version. Some libraries will also have "group ids", which are displayed like this: ```clj [com.cedarsoft.utils.legacy/hibernate "1.3.7"] ``` The group id is the part before the slash. Especially for Java libraries, it's often a reversed domain name. Clojure libraries often use the same group-id and artifact-id (as with clj-http), in which case you can omit the group-id. If there is a library that's part of a larger group (such as `ring-jetty-adapter` being part of the `ring` project), the group-id is often the same across all the sub-projects. ### Snapshot Versions Sometimes versions will end in "-SNAPSHOT". This means that it is not an official release but a development build. Relying on snapshot dependencies is discouraged but is sometimes necessary if you need bug fixes, etc. that have not made their way into a release yet. However, snapshot versions are not guaranteed to stick around, so it's important that non-development releases never depend upon snapshot versions that you don't control. Adding a snapshot dependency to your project will cause Leiningen to actively go seek out the latest version of the dependency daily (whereas normal release versions are cached in the local repository) so if you have a lot of snapshots it will slow things down. Note that some libraries make their group-id and artifact-id correspond with the namespace they provide inside the jar, but this is just a convention. There is no guarantee they will match up at all, so consult the library's documentation before writing your `:require` and `:import` clauses. ### Repositories Dependencies are stored in *artifact repositories*. If you are familiar with Perl's CPAN, Python's Cheeseshop (aka PyPi), Ruby's rubygems.org, or Node.js's NPM, it's the same thing. Leiningen reuses existing JVM repository infrastructure. There are several popular open source repositories. Leiningen by default will use two of them: [clojars.org](https://clojars.org) and [Maven Central](https://search.maven.org/). [Clojars](https://clojars.org/) is the Clojure community's centralized maven repository, while [Central](https://search.maven.org/) is for the wider JVM community. You can add third-party repositories by setting the `:repositories` key in project.clj. See the [sample.project.clj](https://github.com/technomancy/leiningen/blob/stable/sample.project.clj) for examples on how to do so. This sample uses additional repositories such as the Sonatype repository which gives access to the latest SNAPSHOT development version of a library (Clojure or Java). It also contains other relevant settings regarding repositories such as update frequency. ### Checkout Dependencies Sometimes it is necessary to develop two projects in parallel but it is very inconvenient to run `lein install` and restart your repl all the time to get your changes picked up. Leiningen provides a solution called *checkout dependencies* (or just *checkouts*). To use it, create a directory called `checkouts` in the project root, like so: . |-- project.clj |-- README.md |-- checkouts |-- src | `-- my_stuff | `-- core.clj `-- test `-- my_stuff `-- core_test.clj Then, under the checkouts directory, create symlinks to the root directories of projects you need. The names of the symlinks don't matter: Leiningen just follows all of them to find `project.clj` files to use. Traditionally, they have the same name as the directory they point to. . |-- project.clj |-- README.md |-- checkouts | `-- suchwow [link to ~/code/oss/suchwow] | `-- commons [link to ~/code/company/commons] |-- src | `-- my_stuff | `-- core.clj `-- test `-- my_stuff `-- core_test.clj Libraries located under the `checkouts` directory take precedence over libraries pulled from repositories, but this is not a replacement for listing the project in your main project's `:dependencies`; it simply supplements that for convenience. That is, given the above directory hierarchy, `project.clj` should contain something like: :dependencies [[org.clojure/clojure "1.9.0"] ... [suchwow "0.3.9"] [com.megacorp/commons "1.3.5"] ...] Note here that the Maven groupid `com.megacorp` has no effect on the way checkouts work. The `suchwow` and `commons` links look the same in `checkouts`, and the groupid hierarchy doesn't need to appear in the way `commons` is actually laid out on disk. After you've updated `:dependencies`, `lein` will still need to be able to find the library in some repository like clojars or your `~/.m2` directory. If `lein` complains with a message like "Could not find artifact suchwow:jar:0.3.9", it's possible that `project.clj` and `suchwow/project.clj` use different version numbers. It's also possible that you're working on the main project and `suchwow` at the same time, have bumped the version number in both project files, but still have the old version in your local Maven repository. Run `lein install` in the `suchwow` directory. That is: the `suchwow` version number must be the same in *three* places: in suchwow's `project.clj`, in the main project's `project.clj`, *and in some repository the main project uses*. If you change the dependencies of a checkout project you will still have to run `lein install` and restart your repl; it's just that source changes will be picked up immediately. Checkouts are an opt-in feature; not everyone who is working on the project will have the same set of checkouts, so your project should work without checkouts before you push or merge. Make sure not to override the `base` profile while using checkouts. In practice that usually means using `lein with-profile +foo run` rather than `lein with-profile foo run`. ### Search Leiningen supports searching remote Maven repositories for matching jars with the command `lein search $TERM`. Currently only searching Central and Clojars is supported. ### Maven Read Timeout The underlying Maven Wagon transport reads the `maven.wagon.rto` system property to determine the timeout used when downloading artifacts from a repository. The `lein` script sets that property to be 10000. If that timeout isn't long enough (for example, when using a slow corporate mirror), it can be overridden via LEIN_JVM_OPTS: ```bash export LEIN_JVM_OPTS="-Dmaven.wagon.rto=1800000" ``` ## Setting JVM Options To pass extra arguments to the JVM, set the `:jvm-opts` vector. This will override any default JVM opts set by Leiningen. ```clj :jvm-opts ["-Xmx1g"] ``` If you want to pass [compiler options](https://clojure.org/reference/compilation#_compiler_options) to the Clojure compiler, you also do this here. ``` :jvm-opts ["-Dclojure.compiler.disable-locals-clearing=true" "-Dclojure.compiler.elide-meta=[:doc :file :line :added]" ; notice the array is not quoted like it would be if you passed it directly on the command line. "-Dclojure.compiler.direct-linking=true"] ``` You can also pass options to Leiningen in the `JVM_OPTS` environment variable. If you want to provide the Leiningen JVM with custom options, set them in `LEIN_JVM_OPTS`. ## Running Code Enough setup; let's see some code running. Start with a REPL (read-eval-print loop): $ lein repl nREPL server started on port 55568 on host 127.0.0.1 - nrepl://127.0.0.1:55568 REPL-y 0.3.0 Clojure 1.5.1 Docs: (doc function-name-here) (find-doc "part-of-name-here") Source: (source function-name-here) Javadoc: (javadoc java-object-or-class-here) Exit: Control+D or (exit) or (quit) Results: Stored in vars *1, *2, *3, an exception in *e user=> The REPL is an interactive prompt where you can enter arbitrary code to run in the context of your project. Since we've added `clj-http` to `:dependencies`, we are able to load it here along with code from the `my-stuff.core` namespace in your project's own `src/` directory: user=> (require 'my-stuff.core) nil user=> (my-stuff.core/-main) Hello, World! nil user=> (require '[clj-http.client :as http]) nil user=> (def response (http/get "https://leiningen.org")) #'user/response user=> (keys response) (:status :headers :body :request-time :trace-redirects :orig-content-encoding) The call to `-main` shows both println output ("Hello, World!") and the return value (nil) together. Built-in documentation is available via `doc`, and you can examine the source of functions with `source`: user=> (source my-stuff.core/-main) (defn -main "I don't do a whole lot." [& args] (println "Hello, World!")) user=> ; use control+d to exit If you already have code in a `-main` function ready to go and don't need to enter code interactively, the `run` task is simpler: $ lein run Hello, World! Providing a `-m` argument will tell Leiningen to look for the `-main` function in another namespace. Setting a default `:main` in `project.clj` lets you omit `-m`. For long-running `lein run` processes, you may wish to save memory with the higher-order trampoline task, which allows the Leiningen JVM process to exit before launching your project's JVM. $ lein trampoline run -m my-stuff.server 5000 If you have any Java to be compiled in `:java-source-paths` or Clojure namespaces listed in `:aot`, they will always be compiled before Leiningen runs any other code, via any `run`, `repl`, etc. invocations. ## Tests We haven't written any tests yet, but we can run the failing tests included from the project template: $ lein test lein test my-stuff.core-test lein test :only my-stuff.core-test/a-test FAIL in (a-test) (core_test.clj:7) FIXME, I fail. expected: (= 0 1) actual: (not (= 0 1)) Ran 1 tests containing 1 assertions. 1 failures, 0 errors. Tests failed. Once we fill it in the test suite will become more useful. Sometimes if you've got a large test suite you'll want to run just one or two namespaces at a time; `lein test my-stuff.core-test` will do that. You also might want to break up your tests using test selectors; see `lein help test` for more details. Running `lein test` from the command-line is suitable for regression testing, but the slow startup time of the JVM makes it a poor fit for testing styles that require tighter feedback loops. In these cases, either keep a repl open for running the appropriate call to [clojure.test/run-tests](https://clojuredocs.org/clojure.test/run-tests) or look into editor integration such as [clojure-test-mode](https://github.com/technomancy/clojure-mode). Keep in mind that while keeping a running process around is convenient, it's easy for that process to get into a state that doesn't reflect the files on disk—functions that are loaded and then deleted from the file will remain in memory, making it easy to miss problems arising from missing functions (often referred to as "getting slimed"). Because of this it's advised to do a `lein test` run with a fresh instance periodically in any case, perhaps before you commit. ## Profiles Profiles are used to add various things into your project map in different contexts. For instance, during `lein test` runs, the contents of the `:test` profile, if present, will be merged into your project map. You can use this to enable configuration that should only be applied during test runs, either by adding directories containing config files to your classpath via `:resource-paths` or by other means. See `lein help profiles` for more details. Unless you tell it otherwise, Leiningen will merge the default set of profiles into the project map. This includes user-wide settings from your `:user` profile, the `:dev` profile from `project.clj` if present, and the built-in `:base` profile which contains dev tools like nREPL and optimizations which help startup time at the expense of runtime performance. Never benchmark with the default profiles. (See the FAQ entry for "tiered compilation") ## What to do with it Generally speaking, there are three different goals that are typical of Leiningen projects: * An application you can distribute to end-users * A server-side application * A library for other Clojure projects to consume For the first, you typically build an uberjar. For libraries, you will want to have them published to a repository like Clojars or a private repository. For server-side applications it varies as described below. Generating a project with `lein new app myapp` will start you out with a few extra defaults suitable for non-library projects, or you can browse the [available templates on Clojars](https://clojars.org/search?q=lein-template) for things like specific web technologies or other project types. ### Uberjar The simplest thing to do is to distribute an uberjar. This is a single standalone executable jar file most suitable for giving to nontechnical users. For this to work you'll need to specify a namespace as your `:main` in `project.clj` and ensure it's also AOT (Ahead Of Time) compiled by adding it to `:aot`. By this point, our `project.clj` file should look like this: ```clj (defproject my-stuff "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "https://example.com/FIXME" :license {:name "Eclipse Public License" :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"] [clj-http "2.0.0"]] :profiles {:dev {:dependencies [[ring/ring-devel "1.4.0"]]}} :main my-stuff.core :aot [my-stuff.core]) ``` We have also added a development dependency, `ring-devel`. `ring-devel` will not be available in uberjars, and will not be considered a dependency if you publish this project to a repository. The namespace you specify will need to contain a `-main` function that will get called when your standalone jar is run. This namespace should have a `(:gen-class)` declaration in the `ns` form at the top. The `-main` function will get passed the command-line arguments. Let's try something easy in `src/my_stuff/core.clj`: ```clj (ns my-stuff.core (:gen-class)) (defn -main [& args] (println "Welcome to my project! These are your args:" args)) ``` Now we're ready to generate your uberjar: $ lein uberjar Compiling my-stuff.core Created /home/phil/my-stuff/target/uberjar+uberjar/my-stuff-0.1.0-SNAPSHOT.jar Created /home/phil/my-stuff/target/uberjar/my-stuff-0.1.0-SNAPSHOT-standalone.jar This creates a single jar file that contains the contents of all your dependencies. Users can run it with a simple `java` invocation, or on some systems just by double-clicking the jar file. $ java -jar my-stuff-0.1.0-SNAPSHOT-standalone.jar Hello world. Welcome to my project! These are your args: (Hello world.) You can run a regular (non-uber) jar with the `java` command-line tool, but that requires constructing the classpath yourself, so it's not a good solution for end-users. Of course if your users already have Leiningen installed, you can instruct them to use `lein run` as described above. ### Framework (Uber)jars Many Java frameworks expect deployment of a jar file or derived archive sub-format containing a subset of the application's necessary dependencies. The framework expects to provide the missing dependencies itself at run-time. Dependencies which are provided by a framework in this fashion may be specified in the `:provided` profile. Such dependencies will be available during compilation, testing, etc., but won't be included by default by the `uberjar` task or plugin tasks intended to produce stable deployment artifacts. For example, Hadoop job jars may be just regular (uber)jar files containing all dependencies except the Hadoop libraries themselves: ```clj (project example.hadoop "0.1.0" ... :profiles {:provided {:dependencies [[org.apache.hadoop/hadoop-core "1.2.1"]]}} :main example.hadoop) ``` $ lein uberjar Compiling example.hadoop Created /home/xmpl/src/example.hadoop/example.hadoop-0.1.0.jar Created /home/xmpl/src/example.hadoop/example.hadoop-0.1.0-standalone.jar $ hadoop jar example.hadoop-0.1.0-standalone.jar 12/08/24 08:28:30 INFO util.Util: resolving application jar from found main method on: example.hadoop 12/08/24 08:28:30 INFO flow.MultiMapReducePlanner: using application jar: /home/xmpl/src/example.hadoop/./example.hadoop-0.1.0-standalone.jar ... Plugins are required to generate framework deployment jar derivatives (such as WAR files) which include additional metadata, but the `:provided` profile provides a general mechanism for handling the framework dependencies. ### Server-side Projects There are many ways to get your project deployed as a server-side application. Aside from the obvious uberjar approach, simple programs can be packaged up as tarballs with accompanied shell scripts using the [lein-tar plugin](https://github.com/technomancy/lein-tar) and then deployed using [pallet](https://hugoduncan.github.com/pallet/), [chef](https://chef.io/), or other mechanisms. Web applications may be deployed as uberjars using embedded Jetty with `ring-jetty-adapter` or as .war (web application archive) files created by the [lein-ring plugin](https://github.com/weavejester/lein-ring). For things beyond uberjars, server-side deployments are so varied that they are better-handled using plugins rather than tasks that are built-in to Leiningen itself. It's possible to involve Leiningen during production, but there are many subtle gotchas to that approach; it's strongly recommended to use an uberjar if you can. If you need to launch with the `run` task, you should use `lein trampoline run` in order to save memory, otherwise Leiningen's own JVM will stay up and consume unnecessary memory. In addition it's very important to ensure you take steps to freeze all the dependencies before deploying, otherwise it could be easy to end up with [unrepeatable deployments](https://github.com/technomancy/leiningen/wiki/Repeatability). Consider including `~/.m2/repository` in your unit of deployment (tarball, .deb file, etc) along with your project code. It's recommended to use Leiningen to create a deployable artifact in a continuous integration setting. For example, you could have a [Jenkins](https://jenkins-ci.org) CI server run your project's full test suite, and if it passes, upload a tarball to S3. Then deployment is just a matter of pulling down and extracting the known-good tarball on your production servers. Simply launching Leiningen from a checkout on the server will work for the most basic deployments, but as soon as you get a number of servers you run the risk of running with a heterogeneous cluster since you're not guaranteed that each machine will be running with the exact same codebase. Also remember that the default profiles are included unless you specify otherwise, which is not suitable for production. Using `lein trampoline with-profile production run -m myapp.main` is recommended. By default the production profile is empty, but if your deployment includes the `~/.m2/repository` directory from the CI run that generated the tarball, then you should add its path as `:local-repo` along with `:offline? true` to the `:production` profile. Staying offline prevents the deployed project from diverging at all from the version that was tested in the CI environment. Given these pitfalls, it's best to use an uberjar if possible. ### Publishing Libraries If your project is a library and you would like others to be able to use it as a dependency in their projects, you will need to get it into a public repository. While it's possible to [maintain your own private repository](https://github.com/technomancy/leiningen/blob/stable/doc/DEPLOY.md) or get it into [Central](https://search.maven.org), the easiest way is to publish it at [Clojars](https://clojars.org). Once you have [created an account](https://clojars.org/register) there, publishing is easy: $ lein deploy clojars Created ~/src/my-stuff/target/my-stuff-0.1.0-SNAPSHOT.jar Wrote ~/src/my-stuff/pom.xml No credentials found for clojars See `lein help deploying` for how to configure credentials. Username: me Password: Retrieving my-stuff/my-stuff/0.1.0-SNAPSHOT/maven-metadata.xml (1k) from https://clojars.org/repo/ Sending my-stuff/my-stuff/0.1.0-SNAPSHOT/my-stuff-0.1.0-20120531.032047-14.jar (5k) to https://clojars.org/repo/ Sending my-stuff/my-stuff/0.1.0-SNAPSHOT/my-stuff-0.1.0-20120531.032047-14.pom (3k) to https://clojars.org/repo/ Retrieving my-stuff/my-stuff/maven-metadata.xml (1k) from https://clojars.org/repo/ Sending my-stuff/my-stuff/0.1.0-SNAPSHOT/maven-metadata.xml (1k) to https://clojars.org/repo/ Sending my-stuff/my-stuff/maven-metadata.xml (1k) to https://clojars.org/repo/ Once that succeeds it will be available as a package on which other projects may depend. For instructions on storing your credentials so they don't have to be re-entered every time, see `lein help deploying`. When deploying a release that's not a snapshot, Leiningen will attempt to sign it using [GPG](https://gnupg.org) to prove your authorship of the release. See the [deploy guide](https://github.com/technomancy/leiningen/blob/stable/doc/DEPLOY.md). for details of how to set that up. The deploy guide includes instructions for deploying to other repositories as well. ## That's It! Now go start coding your next project! leiningen-2.9.1/doc/ja/000077500000000000000000000000001343535564500146475ustar00rootroot00000000000000leiningen-2.9.1/doc/ja/PLUGINS_ja.md000066400000000000000000001000151343535564500167610ustar00rootroot00000000000000 **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Leiningen プラグイン](#leiningen-%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3) - [プラグインを書く](#%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%92%E6%9B%B8%E3%81%8F) - [タスクの引数](#%E3%82%BF%E3%82%B9%E3%82%AF%E3%81%AE%E5%BC%95%E6%95%B0) - [ドキュメンテーション](#%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3) - [コード評価](#%E3%82%B3%E3%83%BC%E3%83%89%E8%A9%95%E4%BE%A1) - [プロジェクトコンテクスト内での評価](#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AF%E3%82%B9%E3%83%88%E5%86%85%E3%81%A7%E3%81%AE%E8%A9%95%E4%BE%A1) - [他のプラグインコンテンツ](#%E4%BB%96%E3%81%AE%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84) - [プロファイル](#%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB) - [フック](#%E3%83%95%E3%83%83%E3%82%AF) - [プロジェクト ミドルウェア](#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88-%E3%83%9F%E3%83%89%E3%83%AB%E3%82%A6%E3%82%A7%E3%82%A2) - [Maven Wagon](#maven-wagon) - [VCSメソッド](#vcs%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89) - [プラグインの呼び出し](#%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AE%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97) - [Clojureのバージョン](#clojure%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3) - [既存のプラグインのアップグレード](#%E6%97%A2%E5%AD%98%E3%81%AE%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AE%E3%82%A2%E3%83%83%E3%83%97%E3%82%B0%E3%83%AC%E3%83%BC%E3%83%89) - [プロジェクト vs スタンドアロンでの実行](#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88-vs-%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%89%E3%82%A2%E3%83%AD%E3%83%B3%E3%81%A7%E3%81%AE%E5%AE%9F%E8%A1%8C) - [標準タスクの上書き](#%E6%A8%99%E6%BA%96%E3%82%BF%E3%82%B9%E3%82%AF%E3%81%AE%E4%B8%8A%E6%9B%B8%E3%81%8D) - [1.x互換性](#1x%E4%BA%92%E6%8F%9B%E6%80%A7) - [特定のプロジェクト向けタスク](#%E7%89%B9%E5%AE%9A%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E5%90%91%E3%81%91%E3%82%BF%E3%82%B9%E3%82%AF) - [楽しんでください](#%E6%A5%BD%E3%81%97%E3%82%93%E3%81%A7%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84) [English](../PLUGINS.md) # Leiningen プラグイン Leiningenのタスクはleiningen.$TASK名前空間にある$TASKという名前の関数に過ぎません。ですから、Leiningenのプラグインを記述するのは、単にそのような関数を含むプロジェクトを作るだけのことで、下記の内容の多くは、Leiningenそのものに含まれているタスクにも同様に当てはまります。 プラグインを使用するには、プロジェクトマップの`:plugins`にそのプラグインを宣言するだけです。プロジェクトの実行用ではなく、使い勝手を向上させるプラグインは、`project.clj`ファイルに直接記述する代わりに`~/.lein/profiles.clj`の`:user`プロファイルに記述してください。 ## プラグインを書く `lein new plugin myplugin`でプロジェクトを作成するところからはじめ、`leiningen.myplugin`名前空間の`myplugin`関数を編集してください。`project.clj`内にある`:eval-in-leningen true`によって、タスクはサブプロセスではなく、leiningenプロセス内部で動作します。プラグインは、clojureそのものへの依存関係を宣言する必要はありません。 [Leiningen本体の依存関係全て](https://github.com/technomancy/leiningen/blob/stable/project.clj)がプラグインから利用可能です。 非常に単純なプラグインの例として、 [ソースコード内の](https://github.com/technomancy/leiningen/tree/stable/lein-pprint) `lein-pprint`ディレクトリを参照してください。 プラグインの開発中、プロジェクト内で`lein install`を再実行し、それからテストプロジェクトに切り替えるのは非常に手間がかかります。一度プラグインをインストールすれば、テストプロジェクト内の`.lein-classpath`ファイルに、プラグインの`src`ディレクトリのパスを記述しておくことでこの手間を省くことができます。そのプラグインが別の開発中のライブラリに依存している場合は、`.lein-classpath`にUNIXでは`:`、Windowsでは`;`のクラスパスセパレータで区切ってライブラリのディレクトリを追加することができます。 出力をする場合は、`println`の代わりに、`leiningen.core.main/info`、`leiningen.core.main/warn`、`leiningen.core.main/debug`のいずれかを使用してください。ユーザの出力設定の制御が適用されます。 ### タスクの引数 タスク関数の最初の引数は現在のプロジェクトにしてください。これは`project.clj`を元にしたマップですが、`:name`、`:group`、`:version`、`:root`などのキーが追加されています。このプロジェクトマップがどのようなものか確認するためには、`lein-pprint`プラグインを使ってみてください。プロジェクトと、プロファイルの組み合わせを確認するために`pprint`タスクを実行することができます。 コマンドラインからパラメタをとるタスクが必要な場合、ひとつ以上の引数をとる関数を作ることができます。タスクは単なるClojureの関数であることを強調するために、引数は通常、UNIXの伝統的な`--dashed`スタイルでなく、`:keywords`を受け付けるように記述します。引数は全てStringとして渡されることに留意してください。引数をキーワード、シンボル、整数として扱いたい場合には`read-string`を呼び出すことができますが、それはあなたが記述する関数次第です。他のタスクを関数として呼び出す際も、この点を留意してください。 ほとんどのタスクは、他のプロジェクトの内部でのみ実行されます。もしタスクを、プロジェクトディレクトリの外側で実行できるようにしたい場合は、`^:no-project-needed`メタデータをタスク関数に追加してください。その場合であっても、タスク関数の第一引数はプロジェクトをとるように記述し、プロジェクト外で実行した際に渡されるnilを受け入れるようにしてください。プロジェクト内で実行した場合は、LeiningenはJVMを起動する前に、プロジェクトのルートディレクトに`cd`しますが、IDE連携など、`leiningen-core`ライブラリを使用しているツールは同じようにふるまわない可能性があるため、プロジェクトの`:root`キーワードを確認し、そのディレクトリを起点とすると最大限の移植性が得られます。 ### ドキュメンテーション `lein help`タスクはdocstringを使っています。名前空間レベルのdocstringが定義されていれば、それを短いサマリとして使用します。なければ、関数のdocstringの第一文が使用されます。フォーマットの都合上、サマリは68文字以内に収めるようにしてください。関数の引数名も表示されるので、明快で説明的な引数名を選ぶようにしてください。ユーザーに見せたくない代替の引数を持つ場合、関数のメタデータに`:help-arglists`を設定することができます。その場合は全ての引数について説明するようにしてください。引数は全てStringなので、キーワード、数字、シンボルが必要な場合は`read-string`を呼び出す必要があることに留意してください。 複雑なタスクはサブタスクに分割することがよくあります。サブタスクの変数のベクターを含んだ`:subtasks`メタデータをタスク関数に渡すことによって、`lein help $TASK_CONTAINING_SUBTASKS`を実行した際に、サブタスクを表示することができます。サブタスク一覧は、それぞれのサブタスクのdocstringの第一文を表示します。サブタスクの完全版のヘルプは、`lein help $TASK_CONTAINING_SUBTASKS $SUBTASK`で表示することができます。 特別な指定がない場合、Leiningenは`lein $MYTASK help`の呼び出しを横取りして`lein help $MYTASK`に変換します。タスク内で独自のhelpサブタスクを表示したい場合はタスク関数に`^:pass-through-help`メタデータを指定してこのふるまいを無効化することができます。 ## コード評価 プラグインの関数は、Leiningenのプロセス内で実行されるので、既存のLeiningenの関数全てにアクセスすることができます。`leiningen.core.*`名前空間内の、`^:internal`メタデータが付与されていない関数全てとタスク関数は全て公開されているAPIと考えてください。タスク名前空間のタスク以外の関数は内部用で、マイナーバージョンリリースでも変更される可能性があります。 ### プロジェクトコンテクスト内での評価 タスクの多くはプロジェクトのコンテクスト内でコードを実行する必要があります。`leiningen.core.eval/eval-in-project`関数はこの目的で使用されます。この関数はプロジェクト引数、評価するフォーム、そして最後にオプションとして、メインフォームの前に評価される、初期化用のフォームをとることができます。この最後のフォームは[ジラルディシナリオ](https://technomancy.us/143)を防ぐために、名前空間を事前にrequireするために用いることができます。 `eval-in-project`関数内ではプロジェクトのクラスパスが有効になっており、Leiningen自体の内部関数とプラグインは無効化されています。 プロジェクトマップは`eval-in-project`に渡す前に改変することができますが、プロファイルをマージすることで変更する方法が、ユーザーによるオーバーライドを可能にするので推奨されます。変更を加えるために、`leiningen.core.project/merge-profiles`を使用してください。 ```clj (def swank-profile {:dependencies [['swank-clojure "1.4.3"]]}) (defn swank "Launch swank server for Emacs to connect. Optionally takes PORT and HOST." [project port host & opts] (let [profile (or (:swank (:profiles project)) swank-profile) project (project/merge-profiles project [profile])] (eval-in-project project `(swank.core/-main ~@opts) '(require 'swank.core)))) ``` `swank-clojure`依存関係のコードがプロジェクト内で必要なため、独自のプロファイルマップを宣言し、マージしています。しかし、`:swank`プロファイルがプロジェクトマップに定義されている場合はそれを使うため、ユーザはプラグイン内にハードコードされたバージョンに依存したくない場合は自分で違うバージョンを選択することができます。 上記で用いたコードは単に`eval-in-project`と`merge-profiles`をラップしただけなので、プラグインの例としてはふさわしくないことに留意してください。もし実現したいことがこれだけなのであれば、プラグインを実装することなく実現することができます。単に`with-profiles`と必要な関数を呼び出す`run`タスクを使ったエイリアスを定義すればよいのです。 `eval-in-project`を実行する前に、Leiningenは全てのJavaコードと実行に必要なClojureコードをバイトコードに事前にコンパイルして、プロジェクトが実行可能な状態になるよう準備しなければなりません。これはプロジェクトの`:prep-tasks`キーに定義されているタスク全てを実行することで行われます。標準では`["javac" "compile"]`です。もしあなたのプラグインが他の準備作業を必要とする場合、(例えばプロトコルバッファのコンパイル)、ユーザに別のエントリを`:prep-tasks`に追加してもらうよう指示することができます。このタスクは`eval-in-project`を実行するたびに評価されることに留意してください。前回の実行時から何も変わっていなければ素早く終了するように実装してください。 ## 他のプラグインコンテンツ プラグインは主にタスクを提供するためのものですが、他にもプロファイル、フック、ミドルウェア、wagon(依存関係トランスポートメソッド)、バージョン管理方法を含めることができます。 ### プロファイル あなたのプラグインを使用するプロジェクトの多くで必要になりそうなものの、何らかの理由でデフォルトで有効化できない設定があるとき、プラグイン内でプロファイルとして含めることができます。 `src/myplugin/profiles.clj`というファイルをプラグイン内に作成して、下記のマップを定義してください。 ```clj {:default {:x "y and z"} :extra {:other "settings"}} ``` マップ内のそれぞれの値がプロファイルで、ユーザーがプロジェクトにマージすることができます。`with-profile`を用いて、実行時に明示的に指定することができます。 $ lein with-profile plugin.myplugin/extra test ユーザは`:default`プロファイルを変更することで自動的に有効化することもできます。 ```clj :profiles {:default [:base :system :user :provided :dev :plugin.myplugin/default] :other {...}} ``` `:default`プロファイル内のエントリは、`jar`、`uberjar`、`pom`など、下流向けに成果物を生成するタスクと、`with-profile`を指定したタスクを除いた、他の全てのタスクで有効化されます。 ### フック フックを用いて、Leiningen標準タスクのふるまいをある程度変更することができます。フック機能は、Leiningenに含まれている [Robert Hooke](https://github.com/technomancy/robert-hooke)ライブラリによって提供されています。 clojure.testのフィクスチャ機能に着想を得て、フックは他の関数、多くの場合はタスクをラップし、他の変数をバインディングしたり、返り値を改変したり、関数の実行を条件で制御したりすることでふるまいを変えます。`add-hook`関数は適用するタスクの変数とラッピングする関数を引数にとります。 ```clj (ns lein-integration.plugin (:require [robert.hooke] [leiningen.test])) (defn add-test-var-println [f & args] `(binding [~'clojure.test/assert-expr (fn [msg# form#] (println "Asserting" form#) ((.getRawRoot #'clojure.test/assert-expr) msg# form#))] ~(apply f args))) ;; Place the body of the activate function at the top-level for ;; compatibility with Leiningen 1.x (defn activate [] (robert.hooke/add-hook #'leiningen.test/form-for-testing-namespaces #'add-test-var-println)) ``` フックは関数合成(compose)しますので、あなたのフックが他のフックの内側で実行される場合があることに気をつけてください。詳細は [Hookeのドキュメンテーション](https://github.com/technomancy/robert-hooke/blob/master/README.md)を参照してください。`add-hook`への呼び出しは第一、第二引数の両方にVarを用いるべきであることに留意してください。そうすることでフックを重複して追加することなく繰り返しローディング可能になります。これは、Clojureでは関数は同一性が比較できませんが、Varは可能だからです。 もしあなたのフックが、あなたのプラグインを含むプロジェクトで自動的にロードされるようにしたい場合は、`plugin-name.plugin/hooks`関数で呼び出して有効化してください。上記の例ではプラグインは`lein-integration`という名前なので、`lein-integration.plugin/hooks`関数が、`lein-integration`プラグインのロード時に自動的に呼び出されます。 フックは、project.clj内の`:hooks`キーに有効化するためのVarのシークエンスを設定することで、手動でロードすることもできます。下位互換性のために、`:hooks`内でVarの代わりに名前空間も指定しすることもできます。その名前空間内の`activate`関数が呼び出されます。自動ローディングのフックは手動で指定されたフックより前に有効化されます。 ### プロジェクト ミドルウェア プロジェクトミドルウェアは、プロジェクトマップを引数にとり、新しいプロジェクトマップを返す関数にすぎません。ミドルウェアによって、プラグインはプロジェクトマップを変換することができるようになります。しかしミドルウェアは柔軟で透過的なので、デバッグを難しくするという問題点があります。もしプラグイン内のプロファイルを使って必要なことができるのであれば、そのほうがより宣言的で、ふるまいを観察しやすいので、後で起こる頭痛の種を減らすことができます。 下記のミドルウェアはプロジェクトマップの内容をプロジェクトのリソースフォルダ内に挿入してコードから読み取り可能にします。 ```clj (ns lein-inject.plugin) (defn middleware [project] (update-in project [:injections] concat `[(spit "resources/project.clj" ~(prn-str project))])) ``` フックと同様、ミドルウェアも`plugin-name.plugin/middleware`内に定義すれば自動的に適用されます。また、project.clj内の`:middleware`キーにプロジェクトマップを変換するVarのシークエンスを定義することで手動でローディングすることもできます。ミドルウェアの自動ローディングが手動で定義されたミドルウェアよりも前に適用されることに留意してください。 また、現在有効なミドルウェアは有効になっているプロファイルに依存していることにも注意してください。つまりアクティブなプロファイルが切り替わるたびにミドルウェア関数を再適用する必要があるということです。オリジナルのプロジェクトマップを保存しておき、`merge-profiles`、`unmerge-profiles`、`set-profiles`を呼び出すたびに元の状態から変換することによって実現しています。ミドルウェア関数は繰り返し呼び出される可能性があるので、冪等性(idempotent)のない副作用を含むべきでありません。 ### Maven Wagon [Pomegranate](https://github.com/cemerick/pomegranate) (依存解決のためにLeiningenによって用いられているライブラリ)は"wagon"ファクトリの登録をサポートしています。wagonはリポジトリ用の非標準トランスポートプロトコルを扱うために用いられ、リポジトリURLのプロトコルに応じて選択されます。もし、あなたのプラグインがwagonファクトリを登録する必要があるのであれば、プロトコルと、そのプロトコル用のwagonインスタンスを返す関数のマップを含む`leiningen/wagons.clj`ファイルを含めることで実現できます。例えば、下記の`wagons.clj`は`dav:`URL用のwagonファクトリを登録します。 ```clj {"dav" #(org.apache.maven.wagon.providers.webdav.WebDavWagon.)} ``` このテクニックを用いたプラグインの例として、[S3 wagon private](https://github.com/technomancy/s3-wagon-private)や [lein-webdav](https://github.com/tobias/lein-webdav)を参考にしてください。 ### VCSメソッド Leiningenにはマルチメソッドを用いてリリース関連のバージョン管理タスクを行う、`vcs`タスクが含まれています。標準では、Git向けの実装が含まれていますが、`leiningen.vcs.$SYSTEM`名前空間に含めることで他のシステムのサポートを追加することができます。`vcs`タスクが呼び出される際、`leiningen.vcs`プレフィックス配下の名前空間全てがローディングされます。これらの名前空間では、`leiningen.vcs`内で定義されている`defmulti`向けのメソッドのみを特定のバージョン管理システム用に定義するようにしてください。 ## プラグインの呼び出し プラグインをプロジェクト内で用いるためには、`:dependencies`と同じフォーマットで、`:plugins`キーをproject.cljに追加するだけです。`:dependencies`で扱えるオプションに加え、`:plugins`にはフックやミドルウェアの自動ローディングを無効化するオプションが追加されています。 ```clj (defproject foo "0.1.0" :plugins [[lein-pprint "1.1.1"] [lein-foo "0.0.1" :hooks false] [lein-bar "0.0.1" :middleware false]]) ``` ## Clojureのバージョン Leiningen2.4.0以上はClojure1.6.0を使用しています。もしLeiningenのプラグイン内で別のバージョンのClojureを使う必要がある場合は、`eval-in-project`をダミーのプロジェクト引数と共に用いることができます。 ```clj (eval-in-project {:dependencies '[[org.clojure/clojure "1.4.0"]]} '(println "hello from" *clojure-version*)) ``` ## 既存のプラグインのアップグレード Leiningenの以前のバージョンはプラグインの動き方に違いがいくつかありますが、アップグレードをするのはそれほど難しくないはずです。 バージョン1.xと2.xの最も大きな違いは`:dev-dependencies`がなくなったことです。Leiningenのプロセスとプロジェクトのプロセスの両方に存在する依存関係はもはや存在しません。Leiningenは`:plugins`だけを参照し、プロジェクトは`:dependencies`だけを参照します。ただしこれらのマップは現在有効化されているプロファイルによって影響を受ける場合があります。 もしあなたのプロジェクトが`eval-in-project`を使用する必要が全くないのであれば、移植は比較的容易です。移動したLeiningen関数への参照を更新するだけで十分です。`leiningen.util.*`名前空間内の関数は全てなくなり、`leiningen.core`は`leiningen.core.main`に移動しました。 `eval-in-project`を使用しているプラグインについては、プラグインの依存関係とソースコードがプロジェクト内では利用可能ではなくなるということに気をつけてください。もしあなたのプラグインが、プラグインとプロジェクトの両方のコンテクストで実行する必要のあるコードを含んでいる場合は、複数のプロジェクトに分割し、それぞれを`:plugins`と`:dependencies`に登録する必要があります。`eval-in-project`の呼び出しで`:dependencies`を挿入する方法については上記の`lein-swank`の例を参照してください。 ## プロジェクト vs スタンドアロンでの実行 Leiningenタスクの中にはどのディレクトリからでも実行可能なものがあります。(例:`lein repl`)。プロジェクトコンテクスト内でのみ有効なタスクもあります。 Leiningenがプロジェクトのコンテクスト内で実行されているかどうか(つまり、現在のディレクトリに`project.clj`があるかどうか)を調べるには、プロジェクトマップの`:root`キーを調べます。 ``` clojure (if (:root project) (comment "Running in a project directory") (comment "Running standalone")) ``` もしあなたのプラグインがプロジェクトコンテクストの外側で動作するとしても、プロジェクトマップ用の引数リストの余地を残しておくべきです。プロジェクトが存在しない場合はnilが渡ってくるものと考えてください。`^:no-project-needed`メタデータを使って、プロジェクトを必要としてないことを示してください。 Leiningen 1.xでは、数値を返すタスク関数はプロセスのexit値を出力する方法として使われていましたが、2.xでは致命的なエラーが起こった際には`leiningen.core.main/abort`を呼び出すべきです。`leiningen.core.main/*exit-process?*`変数にtrueが設定されている場合、この関数の呼び出しはexitを引き起こしますが、`with-profiles`など、コンテクストによっては、単に例外をスローして次のタスクに進む場合もあります。 ## 標準タスクの上書き 通常は、例えば`leiningen.compile`という名前空間を持つプラグインを作ったとしても、それは`lein compile`を実行した時に呼び出されることはありません。標準タスクがあなたのプラグインを上書きします。もし標準タスクを隠したい場合、エイリアスを作るか、プラグインを`leiningen.plugin.compile`名前空間内に作ることで実現することができます。 ## 1.x互換性 ひとたび2.xとの互換性を確保するのに必要な変更点を特定すれば、同一のコードベース内でバージョン1.xと2.xの両方をサポートするかどうかを決めることができます。別のブランチで管理したほうが楽な場合もありますし、両方のバージョンをサポートしたほうが簡単な場合もあります。幸運なことに、`:plugins`を用いて、`eval-in-project`のためだけに`:dependencies`を追加する戦略はLeiningen 1.7上ではうまく動作します。 もし2.xで移動してしまった関数を使いたい場合は、コンパイル時に解決する代わりに実行時に解決し、もし見つからなければ1.xバージョンの関数に縮退する方法を試してみてください。`lein-swank`プラグインはこの互換性シムを使った例を提供しています。 ```clj (defn eval-in-project "Support eval-in-project in both Leiningen 1.x and 2.x." [project form init] (let [[eip two?] (or (try (require 'leiningen.core.eval) [(resolve 'leiningen.core.eval/eval-in-project) true] (catch java.io.FileNotFoundException _)) (try (require 'leiningen.compile) [(resolve 'leiningen.compile/eval-in-project)] (catch java.io.FileNotFoundException _)))] (if two? (eip project form init) (eip project form nil nil init)))) ``` もちろん、関数がとる引数の数が変わったり、関数が完全になくなった場合はこの手法は適用できませんが、ほとんどの場合はこれで充分なはずです。 2.xで変更された関数のうち、広く用いられていたものは、1.xと2.xの両方をサポートする互換性シムを提供する、[leinjacker](https://github.com/sattvik/leinjacker)プロジェクト経由で利用可能です。 他の重要な変更点として、`:source-path`、`:resources-path`、`:java-source-path`、`:test-path`は、`:source-paths`、`:resource-paths`、`:java-source-paths`、`:test-paths`に変更され、Stringの代わりにベクターをとるようになりました。以前の`:dev-resources`キーは、`:dev`プロファイルが有効な場合のみ`:resource-paths`のエントリの一つとして含まれるようになりました。 後方互換性を保つ方法でタスクをプロジェクトディレクトリの外側で実行させるのは、2.xが単にプロジェクトを引数として渡し、なければnilにしておくのに対し、1.xは必要以上に賢く、引数リストが実際にプロジェクトの引数として渡せるかチェックをするため、簡単ではありません。最初の引数がプロジェクトマップかどうかを判定することはできますが、引数が二つ以上の場合、このチェックは非常に難しくなります。このような状況では、二つのブランチで管理するほうがよいかもしれません。 ### 特定のプロジェクト向けタスク プロジェクトのコードベースにタスクを含めなければいけない場合もときとしてありますが、これは思ったほど頻繁におこることではありません。コマンドラインから実行する必要があるだけなら、プロジェクト内の`-main`関数として実行させ、`lein garble`のようなエイリアスとして起動するほうがはるかに簡単です。 ```clj :aliases {"garble" ["run" "-m" "myproject.garble" "supergarble"]} ``` エイリアスのベクターは部分適用されたタスク関数になりますから、上記の設定の場合、`lein garble seventeen`は、`lein run -m myproject.garble supergarble seventeen`(あるいはreplから`(myproject.garble/-main "supergarble" "seventeen")`を実行した場合)と同等であることに注意してください。エイリアスの引数は実行時に、あらかじめ渡されている引数の後ろに追加されます。 Leiningenタスクを記述する必要があるのは、例えば`eval-in-project`やLeiningenの内部へ直接アクセスするタスクを呼び出す前にプロジェクトマップを調整する必要がある場合など、プロジェクトコンテクストの外側で操作する必要がある場合のみです。エイリアスを使って、プロジェクトマップから値を読み取ることさえできます。 ```clj :aliases {"garble" ["run" "-m" "myproject.garble" :project/version]} ``` この例ではプロジェクトマップの`:version`フィールドを引数リストに渡すことで、プロジェクト内で実行される`-main`関数が値にアクセスできるようにしています。 こういった例の多くは[既存のプラグイン](https://github.com/technomancy/leiningen/wiki/plugins)でカバーされているはずですが、もし類似の例が見つからず、何らかの理由で別のブラグインに分離できない場合、`tasks/leiningen/`の下に新しいタスクを定義した`foo.clj`ファイルを作成し、`tasks`を`.lein-classpath`に追加することでこのふるまいを実現することができます。 ``` $ ls README.md project.clj src tasks test $ ls -R tasks leiningen tasks/leiningen: foo.clj $ echo -ne ":tasks" | cat >> .lein-classpath $ lein foo Hello, Foo! ``` ただし、ほとんどの場合、別のプラグインプロジェクトにタスクを分離するのが望ましいです。`.lein-classpath`は主に実験用か、適切なプラグインを作る時間がない緊急の場合のためにあるものだからです。 ## 楽しんでください あなたのプラグインができあがったら、[Wiki上のリスト](https://github.com/technomancy/leiningen/wiki/plugins)に追加してください。 このプラグインシステムが、あなたの思いのままにLeiningenをカスタマイズするための簡単で、柔軟なシステムを提供していることを願っています。 leiningen-2.9.1/doc/lein.1000066400000000000000000000074211343535564500152720ustar00rootroot00000000000000.\"to render: groff -Tascii -man doc/lein.1 > lein.man" .TH LEININGEN 1 "2017 August 10" .SH NAME lein \- Automate Clojure projects .SH SYNOPSIS .B lein [\fB\-o\fR] [\fB\-U\fR] [\fITASK\fR [\fIARGS\fR]] .br .B lein [\fB\-h\fR|\fB\-\-help\fR] .br .B lein [\fB\-v\fR|\fB\-\-version\fR] .SH DESCRIPTION Leiningen is for automating Clojure projects without setting your hair on fire. Working on Clojure projects with tools designed for Java can be an exercise in frustration. With Leiningen, you just write Clojure. .SH TASKS .B lein help will show the complete list of tasks, while .B lein help TASK shows usage for a specific one. .B lein help tutorial has a detailed walk-through of the various tasks, but the most commonly-used are: .RS .TP .B lein new NAME generate a new project skeleton .TP .B lein test [TESTS] run the tests in the TESTS namespaces, or all tests .TP .B lein repl launch an interactive REPL session in a networked REPL server .TP .B lein uberjar package up the project and its dependencies as a standalone .jar file .TP .B lein install install a project into your local repository .TP .B lein deploy [REPOSITORY] deploy a library to a remote repository .RE .TP Other tasks available include: .RS .TP .B lein change Rewrite project.clj by applying a function. .TP .B lein check Check syntax and warn on reflection. .TP .B lein classpath Print the classpath of the current project. .TP .B lein clean Remove all files from project's target-path. .TP .B lein compile Compile Clojure source into .class files. .TP .B lein deps Download all dependencies. .TP .B lein do [TASK], ... Higher-order task to perform other tasks in succession. .TP .B lein jar Package up all the project's files into a jar file. .TP .B lein javac Compile Java source files. .TP .B lein pom Write a pom.xml file to disk for Maven interoperability. .TP .B lein release Perform :release-tasks. .TP .B lein retest Run only the test namespaces which failed last time around. .TP .B lein run Run a -main function with optional command-line arguments. .TP .B lein search Search remote maven repositories for matching jars. .TP .B lein show-profiles List all available profiles or display one if given an argument. .TP .B lein trampoline [TASK] Run a task without nesting the project's JVM inside Leiningen's. .TP .B lein update-in Perform arbitrary transformations on your project map. .TP .B lein vcs Interact with the version control system. .TP .B lein version Print version for Leiningen and the current JVM. .TP .B lein with-profile [PROFILE] [TASK] Apply the given task with the profile(s) specified. .RE .SH OPTIONS .TP .BI \-o Run a task offline. .TP .BI \-U Run a task after forcing update of snapshots. .TP .BR \-h ", " \-\-help Print this help or help for a specific task. .TP .BR \-v ", " \-\-version Print Leiningen's version. .SH CONFIGURATION Leiningen reads its configuration from the .B project.clj file in your project root. Either use .B lein new to create a fresh project from which to work, or see the exhaustive list of configuration options with \fBlein help sample\fR. You can customize your project map further with profiles; see \fBlein help profiles\fR. .SH BUGS Check https://github.com/technomancy/leiningen/issues to see if your problem is a known issue. If not, please open a new issue on that site or join the mailing list at https://www.freelists.org/list/leiningen. Please include the output of .B lein version as well as your .B project.clj file and as much of the relevant code from your project as possible. .SH COPYING Copyright .if t \(co .if n (C) 2009-2017 Phil Hagelberg and contributors. Distributed under the Eclipse Public License, the same as Clojure uses. See the file /usr/share/doc/leiningen/copyright. .SH AUTHOR This manpage is written by Phil Hagelberg leiningen-2.9.1/lein-pprint/000077500000000000000000000000001343535564500157515ustar00rootroot00000000000000leiningen-2.9.1/lein-pprint/README.md000066400000000000000000000023101343535564500172240ustar00rootroot00000000000000# lein-pprint Pretty-print a representation of the project map. This is a sample of how a simple plugin would work. ## Usage Add `[lein-pprint "1.2.0"]` to `:plugins`. $ lein pprint ```clj {:compile-path "/home/phil/src/leiningen/lein-pprint/classes", :group "lein-pprint", :source-path ("/home/phil/src/leiningen/lein-pprint/src"), :dependencies nil, :target-path "/home/phil/src/leiningen/lein-pprint/target", :name "lein-pprint", :root "/home/phil/src/leiningen/lein-pprint", :version "1.0.0", :jar-exclusions [#"^\."], :test-path ("/home/phil/src/leiningen/lein-pprint/test"), :repositories (["central" {:url "https://repo1.maven.org/maven2"}] ["clojars" {:url "http://clojars.org/repo/"}]), :uberjar-exclusions [#"^META-INF/DUMMY.SF"], :eval-in :leiningen, :plugins [[lein-swank "1.4.0-SNAPSHOT"]], :resources-path ("/home/phil/src/leiningen/lein-pprint/dev-resources" "/home/phil/src/leiningen/lein-pprint/resources"), :native-path "/home/phil/src/leiningen/lein-pprint/native", :description "Pretty-print a representation of the project map."} ``` ## License Copyright © 2012-2017 Phil Hagelberg and contributors. Distributed under the Eclipse Public License, the same as Clojure. leiningen-2.9.1/lein-pprint/project.clj000066400000000000000000000004311343535564500201070ustar00rootroot00000000000000(defproject lein-pprint "1.2.0" :description "Pretty-print a representation of the project map." :url "https://github.com/technomancy/leiningen" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :eval-in-leiningen true) leiningen-2.9.1/lein-pprint/src/000077500000000000000000000000001343535564500165405ustar00rootroot00000000000000leiningen-2.9.1/lein-pprint/src/leiningen/000077500000000000000000000000001343535564500205105ustar00rootroot00000000000000leiningen-2.9.1/lein-pprint/src/leiningen/pprint.clj000066400000000000000000000022621343535564500225200ustar00rootroot00000000000000(ns leiningen.pprint (:require [clojure.pprint :as pprint] [leiningen.core :refer [abort]])) (defn ^:no-project-needed pprint "Usage: pprint [--not-pretty] [--] [selector...] When no selectors are specified, pretty-prints a representation of the entire project map. Otherwise pretty-prints the item(s) retrieved by (get-in project selector) when reading a selector produces something sequential, or (get project selector) when it doesn't. If \"--not-pretty\" is specified, doesn't pretty-print, just prints." [project & keys] (let [[pretty? keys] (loop [args args pretty? true] (if-let [[arg & args] (seq args)] (case arg "--" [pretty? args] "--no-pretty" (recur false args) (abort "Unrecognized argument" (pr-str arg))))) show (if pretty? pprint/pprint println)] (if (seq keys) (doseq [kstr keys] (let [k (read-string kstr)] (show (if (sequential? k) (get-in project k) (get project k))))) (show project))) (flush)) leiningen-2.9.1/lein-pprint/test/000077500000000000000000000000001343535564500167305ustar00rootroot00000000000000leiningen-2.9.1/lein-pprint/test/leiningen/000077500000000000000000000000001343535564500207005ustar00rootroot00000000000000leiningen-2.9.1/lein-pprint/test/leiningen/pprint_test.clj000066400000000000000000000004041343535564500237430ustar00rootroot00000000000000(ns leiningen.pprint-test (:require [clojure.test :refer :all] [leiningen.pprint :refer :all])) (deftest can-pprint (is (= "1\n" (with-out-str (pprint {:foo 1} ":foo")))) (is (= "1\n" (with-out-str (pprint {:foo {:bar 1}} "[:foo :bar]"))))) leiningen-2.9.1/leiningen-core/000077500000000000000000000000001343535564500164065ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/README.md000066400000000000000000000067531343535564500177000ustar00rootroot00000000000000# Leiningen Core This library provides the core functionality of Leiningen. This consists of the task execution implementation, project configuration, and helper functions. The built-in tasks and the launcher scripts are kept in the main `leiningen` project. More detailed [API reference](https://leiningen.org/reference.html) is available. ## Namespaces * **leiningen.core.main** contains the `-main` entry point along with task handling functions like `apply-task` and `resolve-task`. * **leiningen.core.project** has `read` and `defproject` for getting a project map from `project.clj` files. It also handles applying profiles to the project map and loading plugins. * **leiningen.core.classpath** is where the project's classpath is calculated. It handles Maven dependencies as well as checkout dependencies. * **leiningen.core.eval** houses the `eval-in-project` function which implements the isolation of project code from Leiningen's own code. * **leiningen.core.user** just has a handful of functions which handle user-level configuration. ## Running Tasks When Leiningen is invoked, it first reads the `project.clj` file and applies any active profiles to the resulting project map. (See Leiningen's own readme for a description of how profiles work.) Then it looks up the task which was invoked. Tasks are just functions named after the task they implement and defined in the `leiningen.the-task` namespace. They usually take a project map as their argument, but can also run outside the context of a project. See the [plugin guide](https://github.com/technomancy/leiningen/blob/stable/doc/PLUGINS.md) for more details on how tasks are written. The `apply-task` function looks up the task function, checks to make sure it can be applied to the provided arguments, and then calls it. ## Project Isolation When you launch Leiningen, it must start an instance of Clojure to load itself. But this instance must not affect the project that you're building. It may use a different version of Clojure or other dependencies from Leiningen itself, and Leiningen's code should not be visible to the project's functions. Leiningen currently implements this by launching a sub-process using `leiningen.core.eval/eval-in-project`. Any code that must execute within the context of the project (AOT compilation, test runs, repls) needs to go through this function. Before the process is launched, the project must be "prepped", which consists of running all the tasks named in the project's `:prep-tasks` key. This defaults to `javac` and `compile`, but `defproject` or profiles may add additional tasks as necessary. All prep tasks must be cheap to call if nothing has changed since their last invocation. The sub-process (referred to as the "project JVM") is an entirely new invocation of the `java` command with its own classpath calculated from functions in the `leiningen.core.classpath` namespace. It can even use a different version of the JVM from Leiningen if the `:java-cmd` key is provided. It can only communicate with Leiningen's process via the file system, sockets, and its exit code. The exception to this rule is when `:eval-in-leiningen` in `project.clj` is true, as is commonly used for Leiningen plugins. Since Leiningen plugins are intended to be used inside Leiningen itself, there's no need to enforce this isolation. ## License Copyright © 2011-2017 Phil Hagelberg and [contributors](https://www.ohloh.net/p/leiningen/contributors). Distributed under the Eclipse Public License, the same as Clojure. leiningen-2.9.1/leiningen-core/dev-resources/000077500000000000000000000000001343535564500211745ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/dev-resources/checkouts/000077500000000000000000000000001343535564500231645ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/dev-resources/checkouts/lib1/000077500000000000000000000000001343535564500240135ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/dev-resources/checkouts/lib1/project.clj000066400000000000000000000001111343535564500261440ustar00rootroot00000000000000(defproject checkout-lib1 "0.0.1" :description "Test some checkouts.") leiningen-2.9.1/leiningen-core/dev-resources/checkouts/lib2/000077500000000000000000000000001343535564500240145ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/dev-resources/checkouts/lib2/project.clj000066400000000000000000000001111343535564500261450ustar00rootroot00000000000000(defproject checkout-lib2 "0.0.1" :description "Test some checkouts.") leiningen-2.9.1/leiningen-core/dev-resources/leiningen/000077500000000000000000000000001343535564500231445ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/dev-resources/leiningen/downloads.clj000066400000000000000000000074361343535564500256420ustar00rootroot00000000000000(use '[cemerick.pomegranate :only (add-dependencies)]) (add-dependencies :coordinates '[[clj-aws-s3 "0.3.6"] [tentacles "0.2.4"]] :repositories (merge cemerick.pomegranate.aether/maven-central {"clojars" "https://clojars.org/repo"})) (ns leiningen.downloads "Calculate download statistics from logs." (:require [aws.sdk.s3 :as s3] [clojure.java.io :as io] [tentacles.repos :as repo] [clojure.pprint :refer [pprint]] [leiningen.core.main :as main]) (:import (java.io File))) (defn ^:internal aws-cred [] ;; in order to run, you need to define a map with the appropriate AWS ;; credentials in ~/.secrets/leiningen_downloads_aws_cred.clj: ;; {:access-key "AWS_ACCESS_KEY" ;; :secret-key "AWS_SECRET_KEY"} (let [f (File. (System/getenv "HOME") "/.secrets/leiningen_downloads_aws_cred.clj")] (if (.exists f) (read-string (slurp f)) (main/abort "Missing credentials file:" f)))) (defn- list-all-objects [bucket & [objects next-marker]] (let [response (s3/list-objects (aws-cred) bucket {:marker next-marker}) truncated? (:truncated? response) next-marker (:next-marker response) objects (concat objects (:objects response))] (if (not truncated?) objects (recur bucket [objects next-marker])))) (defn- fetch-all-objects [bucket] (for [object (list-all-objects bucket)] (do (println (str "Processing: " (:key object))) (s3/get-object (aws-cred) bucket (:key object))))) (defn- file-for-line [line] (let [[_ file] (re-find #"\"GET ([^ ]+) " line)] (if file (last (.split file "/"))))) (defn- ip-for-line [line] (re-find #"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b" line)) (defn- status-for-line [line] (second (re-find #"\" (\d\d\d)" line))) (defn- parse-files [content] (with-open [rdr (io/reader content)] (doall (for [line (line-seq rdr)] {:file (file-for-line line) :status (status-for-line line) :ip (ip-for-line line)})))) (defn- s3-downloads [] (flatten (for [logfile (map :content (fetch-all-objects "leiningen-logs"))] (filter #(and (get % :file) ;; file is present (re-find #"\.jar\b" (get % :file)) ;; file is a jar (= "200" (get % :status))) ;; and only HTTP 200 responses (parse-files logfile))))) (defn- github-downloads [] (reverse (sort-by #(first (vals %)) (filter #(re-find #"\.jar$" (first (keys %))) (let [downloads {}] (for [download (repo/downloads "technomancy" "leiningen")] (assoc downloads (:name download) (:download_count download)))))))) (defn ^:no-project-needed downloads [project] (let [s3-downloads (s3-downloads) s3-download-count (count s3-downloads) github-downloads (github-downloads) github-download-count (reduce + (map #(first (vals %)) github-downloads))] (println (str "GitHub Downloads: " github-download-count)) (println (str "S3 Downloads: " s3-download-count)) (println (str "Unique IP Addresses (S3 Downloads Only): " (count (distinct (map :ip s3-downloads))))) (println (str "Total Downloads: " (+ github-download-count s3-download-count))) (print "\n\n") (println "GitHub downloads by file:") (print "\n\n") (pprint github-downloads) (print "\n\n") (println "S3 downloads by file:") (print "\n\n") (pprint (frequencies (map :file s3-downloads))) (println ""))) ;; need this last println for some reason or else ;; the above doesn't print out using lein run... leiningen-2.9.1/leiningen-core/dev-resources/p1.clj000066400000000000000000000011371343535564500222100ustar00rootroot00000000000000(defproject leiningen "2.0.0-SNAPSHOT" :description "Automate Clojure projects without setting your hair on fire." :url "https://github.com/technomancy/leiningen" :license {:name "Eclipse Public License"} :dependencies [[leiningen-core "2.0.0-SNAPSHOT"] [clucy "0.2.2" :exclusions [org.clojure/clojure]] [lancet "1.0.1"] [robert/hooke "1.1.2"] [stencil "0.2.0"] ["net.3scale/3scale-api" "3.0.2"] ["clj-http" "3.4.1"]] :twelve ~(+ 6 2 4) :disable-implicit-clean true :eval-in-leiningen true) leiningen-2.9.1/leiningen-core/dev-resources/p2.clj000066400000000000000000000001721343535564500222070ustar00rootroot00000000000000(defproject middler "0.0.1" :description "Test some middleware." :middleware [leiningen.core.test.project/add-seven]) leiningen-2.9.1/leiningen-core/dev-resources/p3.clj000066400000000000000000000002511343535564500222060ustar00rootroot00000000000000(defproject middlest "0.0.1" :description "Test explicit middleware inside a plugin." :plugins [[lein-maven "0.1.0"]] :middleware [leiningen.mvn/maven-checkouts]) leiningen-2.9.1/leiningen-core/dev-resources/profile-metadata.clj000066400000000000000000000012671343535564500251120ustar00rootroot00000000000000(defproject metadata-check "0.1.0" :description "Check that profile metadata is retained." :license {:name "Eclipse Public License"} :dependencies [[leiningen-core "2.0.0-SNAPSHOT"] [clucy "0.2.2" :exclusions [org.clojure/clojure]] [lancet "1.0.1"] [robert/hooke "1.1.2"] [stencil "0.2.0"]] :profiles {:bar {:dependencies ^:please-keep-me [[lancet "1.0.2"] [stencil "0.3.0"]] :repositories ^:replace []} :baz {:dependencies ^:hello [] :repositories ^:displace [] :java-opts ["my" "java" "opts"]}}) leiningen-2.9.1/leiningen-core/dev-resources/replace-repositories.clj000066400000000000000000000004371343535564500260320ustar00rootroot00000000000000(defproject metadata-check "0.1.0" :description "Check that repositories can be replaced." :license {:name "Eclipse Public License"} :dependencies [[robert/hooke "1.1.2"] [stencil "0.2.0"]] :repositories ^:replace [["nexus" {:url "https://clojars.org/repo/"}]]) leiningen-2.9.1/leiningen-core/pom.xml000066400000000000000000000070451343535564500177310ustar00rootroot00000000000000 4.0.0 leiningen-core leiningen-core jar 2.9.1 leiningen-core Library for core functionality of Leiningen. https://github.com/technomancy/leiningen Eclipse Public License http://www.eclipse.org/legal/epl-v10.html 0dee13d1b339cf7163c512827ee939c264d64378 src test resources resources target target/classes central https://repo1.maven.org/maven2/ false true clojars https://clojars.org/repo/ true true org.clojure clojure 1.10.0 timofreiberg bultitude 0.3.0 org.clojure clojure org.flatland classlojure 0.7.1 robert hooke 1.3.0 com.cemerick pomegranate 1.1.0 org.slf4j jcl-over-slf4j com.hypirion io 0.3.1 org.slf4j slf4j-nop 1.7.25 org.clojure tools.macro 0.1.5 leiningen-2.9.1/leiningen-core/project.clj000066400000000000000000000021161343535564500205460ustar00rootroot00000000000000(defproject leiningen-core "2.9.1" :url "https://github.com/technomancy/leiningen" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :description "Library for core functionality of Leiningen." ;; If you update these, update resources/leiningen/bootclasspath-deps.clj too :dependencies [[org.clojure/clojure "1.10.0"] [timofreiberg/bultitude "0.3.0" :exclusions [org.clojure/clojure]] [org.flatland/classlojure "0.7.1"] [robert/hooke "1.3.0"] [com.cemerick/pomegranate "1.1.0" :exclusions [org.slf4j/jcl-over-slf4j]] [com.hypirion/io "0.3.1"] [org.slf4j/slf4j-nop "1.7.25"] ; wagon-http uses slf4j ;; we pull this in transitively but want a newer version [org.clojure/tools.macro "0.1.5"]] :scm {:dir ".."} :dev-resources-path "dev-resources" :aliases {"bootstrap" ["with-profile" "base" "do" "install," "classpath" ".lein-bootstrap"]}) leiningen-2.9.1/leiningen-core/resources/000077500000000000000000000000001343535564500204205ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/resources/clojars.pem000066400000000000000000000042331343535564500225620ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIGLjCCBRagAwIBAgIQD6pvsYX5h3q223XlA/jIWDANBgkqhkiG9w0BAQsFADBe MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMR0wGwYDVQQDExRSYXBpZFNTTCBSU0EgQ0EgMjAxODAe Fw0xODA1MjQwMDAwMDBaFw0yMDA2MTcxMjAwMDBaMBYxFDASBgNVBAMTC2Nsb2ph cnMub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1m+pJIzATOEM f2PV95975eoUs25u8wfjGXsL918KuG5c1S/uNAGInTKyZ2ynz/hekeKxCevwhT7l y9mhfdZf0HxWNuL9YTscjSLZkggTCJdFIjCnlI5dbiilN+YEWNY4wh+bAe9C3PG6 HpgHMWuLEmwC7XvL9B4VmvcwifRyqMOhZUoiC+IP+8TAI+WVFbCUzIki5kT2AUcz dk7pLOLl/VFbl6z6bDBbr1l1/FdN/qZL9KitVYF5nSz4wtLfVJKaFnoTmtZjCr30 ItYwa6OU9L3mS1PQZrU1Ec5iXKnPlCsw2ssJE+IZ3EAD4TOLUE8RB1V7xoRE+ptr LmhR0m+lqwIDAQABo4IDLjCCAyowHwYDVR0jBBgwFoAUU8oXWfxrwAMhLxqu5Kqo HIJW2nUwHQYDVR0OBBYEFL5wB7hnK0rB5QTIUOIV8gLPy3bQMCcGA1UdEQQgMB6C C2Nsb2phcnMub3Jngg93d3cuY2xvamFycy5vcmcwDgYDVR0PAQH/BAQDAgWgMB0G A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA+BgNVHR8ENzA1MDOgMaAvhi1o dHRwOi8vY2RwLnJhcGlkc3NsLmNvbS9SYXBpZFNTTFJTQUNBMjAxOC5jcmwwTAYD VR0gBEUwQzA3BglghkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu ZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgEwdQYIKwYBBQUHAQEEaTBnMCYGCCsG AQUFBzABhhpodHRwOi8vc3RhdHVzLnJhcGlkc3NsLmNvbTA9BggrBgEFBQcwAoYx aHR0cDovL2NhY2VydHMucmFwaWRzc2wuY29tL1JhcGlkU1NMUlNBQ0EyMDE4LmNy dDAJBgNVHRMEAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgDuS723dc5g uuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAWOT7sWAAAAEAwBHMEUCIQCwtF4e iM/IRHTa4dbhNbu+zXhJqznE+0pdle4IImlbXQIgGzZDhLXbczJb6pVBPE35HmDN +XDvVeCN+d465ybNtNUAdgCHdb/nWXz4jEOZX73zbv9WjUdWNv9KtWDBtOr/XqCD DwAAAWOT7sXMAAAEAwBHMEUCIQDmQH+ZTAa+OcjqqOyXTKX+GWqXAkLzYj4lmzHb 0jhsqwIgXFNNDS12sP4T/RuOsNfkEHIwoc0PK+K3eyro6VR9yWIAdgC72d+8H4px tZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWOT7sVYAAAEAwBHMEUCIDedm7tm 0jIQbHxBdXsf/Fh0GZKwEXVh04BjDbZfFqT4AiEAi7YDFApSiEGlU42+aoGjLqfI T4TLLvM2TQw6Umz7UwQwDQYJKoZIhvcNAQELBQADggEBAEF+oP8E7mBtivA2nYfE FmmqvUS3UyfDGI1tKcRKiKYe0synD5TMg/Tuc9nK6uC0C7oPmuE8CUHOieRR5wdh UQ8ORIuagiaqE3ONd4kobw/FRWPf9GHxDXPE1LIHVy9x8S/Y/QcPWQ5WDW5n4nv1 sX24YqCM5RG0MaRZ7xIS14dEOMopjyfJszo4RVDX5AfeeLojsIBkbnH0NT7r03+f /nS3Gs+15xC7PJzpQLoD2e7QGR3Oc6x8KavuWgdE7kC///tOAOql3kel8sWrATCa zo4GP8HNLdRJjVnFhwIGV45vHWLD1G2UrzXhXA3uOaKcK909pxQjwLWCBOgDerBW tBc= -----END CERTIFICATE-----leiningen-2.9.1/leiningen-core/src/000077500000000000000000000000001343535564500171755ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/src/leiningen/000077500000000000000000000000001343535564500211455ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/src/leiningen/core/000077500000000000000000000000001343535564500220755ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/src/leiningen/core/classpath.clj000066400000000000000000000667621343535564500245720ustar00rootroot00000000000000(ns leiningen.core.classpath "Calculate project classpaths by resolving dependencies via Aether." (:require [cemerick.pomegranate.aether :as aether] [cemerick.pomegranate :as pomegranate] [clojure.java.io :as io] [clojure.string :as str] [clojure.set :as set] [leiningen.core.user :as user] [leiningen.core.utils :as utils] [leiningen.core.pedantic :as pedantic]) (:import (java.util.jar JarFile) (org.eclipse.aether.resolution DependencyResolutionException))) (defn- warn [& args] ;; TODO: remove me once #1227 is merged (require 'leiningen.core.main) (apply (resolve 'leiningen.core.main/warn) args)) (def ^:private warn-once (memoize warn)) (defn ^:deprecated extract-native-deps [files native-path native-prefixes] (doseq [file files :let [native-prefix (get native-prefixes file "native/") jar (try (JarFile. file) (catch Exception e (throw (Exception. (format "Problem opening jar %s" file) e))))] entry (enumeration-seq (.entries jar)) :when (.startsWith (.getName entry) native-prefix)] (let [f (io/file native-path (subs (.getName entry) (count native-prefix)))] (if (.isDirectory entry) (utils/mkdirs f) (do (utils/mkdirs (.getParentFile f)) (io/copy (.getInputStream jar entry) f)))))) (defn extract-native-dep! "Extracts native content into the native path. Returns true if at least one file was extracted." [native-path file native-prefix] (let [native? (volatile! false) native-prefix (or native-prefix "native/") jar (try (JarFile. file) (catch Exception e (throw (Exception. (format "Problem opening jar %s" file) e))))] (doseq [entry (enumeration-seq (.entries jar)) :when (.startsWith (.getName entry) native-prefix)] (vreset! native? true) (let [f (io/file native-path (subs (.getName entry) (count native-prefix)))] (if (.isDirectory entry) (utils/mkdirs f) (do (utils/mkdirs (.getParentFile f)) (io/copy (.getInputStream jar entry) f))))) @native?)) (defn- stale-extract-native-deps "Extract native dependencies by comparing what has already been extracted to avoid redoing work. If stale files end up in some native path, new or old, the user will receive a warning -- we cannot delete files as the native path may be used for other things as well (or stuff generated earlier may be put in there)." [{old-deps :dependencies old-native-path :native-path} new-raw-deps relative-native-path native-path] (let [renamed-old-deps (utils/map-vals old-deps #(set/rename-keys % {:vsn :old-vsn :native-prefix :old-native-prefix :native? :old-native?})) renamed-new-raw-deps (utils/map-vals new-raw-deps #(set/rename-keys % {:vsn :new-vsn :native-prefix :new-native-prefix :file :new-file})) join (merge-with merge renamed-old-deps renamed-new-raw-deps) new-native-path? (and old-native-path (not= (io/file old-native-path) (io/file relative-native-path))) maybe-stale (volatile! false)] ;; Why all the warnings? Well, we cannot really delete a directory, as it ;; may be populated by things created by others, either in a prep-step ;; before us OR as manual work (adding some self-made native stuff into ;; said). :native-path does not have to be in :target, which makes this ;; stuff kind of hard to avoid. However, it is likely that this path is in ;; the :target-path, which makes life easier for us. TODO: Fix this up for ;; Lein 3.0 by enforcing native to be inside :target-path and stating that ;; it should only be used by native deps. (when new-native-path? (warn "Warning: You changed :native-path to" (pr-str relative-native-path) ", but old native data is still available at" (pr-str old-native-path)) (vreset! maybe-stale true) (doseq [[_ {:keys [native-prefix file]}] new-raw-deps] (extract-native-dep! native-path file native-prefix))) (let [newly-extracted-deps (->> (for [[dep {:keys [old-vsn old-native-prefix old-native? new-vsn new-native-prefix new-file]}] join] (cond (and (= old-vsn new-vsn) ;; no change, stuff already in directory (= old-native-prefix new-native-prefix)) [dep {:vsn old-vsn :native-prefix old-native-prefix :native? old-native?}] (nil? old-vsn) ;; no old version, attempt to extract (let [native? (extract-native-dep! native-path new-file new-native-prefix)] [dep {:vsn new-vsn :native-prefix new-native-prefix :native? native?}]) (nil? new-vsn) ;; dependency was removed (when (and (not new-native-path?) old-native?) (vreset! maybe-stale true) (warn "Warning:" dep old-vsn "will still have its native content in :native-path")) ;; prefix changed (possibly version as well) (not= old-native-prefix new-native-prefix) (let [native? (extract-native-dep! native-path new-file new-native-prefix)] (when (and (not new-native-path?) old-native?) (vreset! maybe-stale true) (warn "Warning:" dep "had its native prefix changed, but content" "from" (pr-str old-native-prefix) "is still in :native-path")) [dep {:vsn new-vsn :native-prefix new-native-prefix :native? native?}]) ;; version changed (all options are now exhausted) (not= old-vsn new-vsn) (let [native? (extract-native-dep! native-path new-file new-native-prefix)] (when (and (not new-native-path?) old-native?) (vreset! maybe-stale true) (warn "Warning: Native dependencies from the old version of" dep (str "(" old-vsn ") is still in :native-path"))) [dep {:vsn new-vsn :native-prefix new-native-prefix :native? native?}]))) (filter identity) (into {}))] (when @maybe-stale (warn " Consider doing `lein clean` to remove potentially stale native files")) {:native-path relative-native-path :dependencies newly-extracted-deps}))) (defn- read-string-or-error "Like read-string, but will return ::error if the reader threw an error." [s] (try (read-string s) (catch Exception e ::error))) (defn outdated-swap! "Performs f if cmp-val is not equal to the old compare value. f is then called with (f outdated-val args...). If no previous cached result is found, then outdated-val is set to nil. The comparison value and cached value is stored in :target-path/stale/`identifier`. Make sure your identifier is unique, e.g. by providing your namespace and function name. The values will be read through read-string and printed with pr-str. outdated-swap! will not run outside of projects." [project identifier cmp-val f & args] (when (and (:root project) (:target-path project)) (let [file (io/file (:target-path project) "stale" identifier) file-content (if (.exists file) (read-string-or-error (slurp file))) [old-cmp-val outdated-val] (if (not= ::error file-content) file-content)] (when (= ::error file-content) (warn "Could not read the old stale value for" identifier ", rerunning stale task")) (when (or (= ::error file-content) (not= old-cmp-val cmp-val)) (utils/mkdirs (.getParentFile file)) (let [result (apply f outdated-val args)] (spit file (pr-str [cmp-val result])) result))))) (defn ^:deprecated when-stale "DEPRECATED: Use outdated-swap! instead. Call f with args when keys in project.clj have changed since the last run. Stores value of project keys in stale directory inside :target-path. Because multiple callers may check the same keys, you must also provide a token to keep your stale value separate. Returns true if the code was executed and nil otherwise." [token keys project f & args] (warn "leiningen.core.classpath/when-stale is deprecated, use outdated-swap! instead.") (let [file (io/file (:target-path project) "stale" (str (name token) "." (str/join "+" (map name keys)))) current-value (pr-str (map (juxt identity project) keys)) old-value (and (.exists file) (slurp file))] (when (and (:name project) (:target-path project) (not= current-value old-value)) (apply f args) (utils/mkdirs (.getParentFile file)) (spit file (doall current-value)) true))) ;; The new version of aether (lein 2.8.0+) is more strict about authentication ;; settings; it will ignore :passphrase if :private-key-file is not set. ;; s3-wagon-private uses :passphrase, so if you've got a private s3 repo, we'll ;; set :private-key-file to an empty string here so that aether will allow the ;; wagon to see it instead of silently discarding it. (defn- hack-private-key [repo] (if-not (re-find #"^s3p" (:url repo "")) repo (update repo :private-key-file #(or % "")))) (defn add-repo-auth "Repository credentials (a map containing some of #{:username :password :passphrase :private-key-file}) are discovered from: 1. Looking up the repository URL in the ~/.lein/credentials.clj.gpg map 2. Scanning that map for regular expression keys that match the repository URL. So, a credentials map that contains an entry: {#\"http://maven.company.com/.*\" {:username \"abc\" :password \"xyz\"}} would be applied to all repositories with URLs matching the regex key that didn't have an explicit entry." [[id repo]] [id (-> repo user/profile-auth user/resolve-credentials hack-private-key)]) (defn get-non-proxy-hosts [] (let [system-no-proxy (System/getenv "no_proxy") lein-no-proxy (System/getenv "http_no_proxy")] (if (and (empty? lein-no-proxy) (not-empty system-no-proxy)) (->> (str/split system-no-proxy #",") (map #(str "*" %)) (str/join "|")) (System/getenv "http_no_proxy")))) (defn get-proxy-settings "Returns a map of the JVM proxy settings" ([] (get-proxy-settings "http_proxy")) ([key] (let [proxy (System/getenv key)] (when-not (str/blank? proxy) (let [url (utils/build-url proxy) user-info (.getUserInfo url) [username password] (and user-info (.split user-info ":"))] {:host (.getHost url) :port (.getPort url) :username username :password password :non-proxy-hosts (get-non-proxy-hosts)}))))) (defn- update-policies [update checksum [repo-name opts]] [repo-name (merge {:update (or update :daily) :checksum (or checksum :fail)} opts)]) (defn- print-failures [e] (doseq [result (.getArtifactResults (.getResult e)) :when (not (.isResolved result)) exception (.getExceptions result)] (warn (.getMessage exception))) (doseq [ex (.getCollectExceptions (.getResult e)) ex2 (.getExceptions (.getResult ex))] (warn (.getMessage ex2)))) (defn- root-cause [e] (last (take-while identity (iterate (memfn getCause) e)))) (def ^:private ^:dynamic *dependencies-session* "This is dynamic in order to avoid memoization issues.") (defn- get-dependencies* [dependencies-key managed-dependencies-key {:keys [repositories local-repo offline? update checksum mirrors] :as project} {:keys [add-classpath?] :as args}] {:pre [(every? vector? (get project dependencies-key)) (every? vector? (get project managed-dependencies-key))]} (try ((if add-classpath? pomegranate/add-dependencies aether/resolve-dependencies) :repository-session-fn *dependencies-session* :local-repo local-repo :offline? offline? :repositories (->> repositories (map add-repo-auth) (map (partial update-policies update checksum))) :managed-coordinates (get project managed-dependencies-key) :coordinates (get project dependencies-key) :mirrors (->> mirrors (map add-repo-auth) (map (partial update-policies update checksum))) :transfer-listener (bound-fn [e] (let [{:keys [type resource error]} e] (let [{:keys [repository name size trace]} resource] (let [aether-repos (if trace (.getRepositories (.getData trace)))] (case type :started (if-let [repo (first (filter #(or (= (.getUrl %) repository) ;; sometimes the "base" url ;; doesn't have a slash on it (= (str (.getUrl %) "/") repository)) aether-repos))] (locking *err* (warn "Retrieving" name "from" (.getId repo))) ;; else case happens for metadata files ) nil))))) :proxy (get-proxy-settings)) (catch DependencyResolutionException e ;; Cannot recur from catch/finally so have to put this in its own defn (print-failures e) (warn "This could be due to a typo in :dependencies, file system permissions, or network issues.") (warn "If you are behind a proxy, try setting the 'http_proxy' environment variable.") (throw (ex-info "Could not resolve dependencies" {:suppress-msg true :exit-code 1} e))) (catch Exception e (let [exception-cause (root-cause e)] (if (and (or (instance? java.net.UnknownHostException exception-cause) (instance? java.net.NoRouteToHostException exception-cause)) (not offline?)) (get-dependencies* dependencies-key managed-dependencies-key (assoc project :offline? true) args) (throw e)))))) (def ^:private get-dependencies-memoized (memoize get-dependencies*)) (defn ^:internal get-dependencies [dependencies-key managed-dependencies-key project & args] (let [ranges (atom []), overrides (atom []) trimmed (select-keys project [dependencies-key managed-dependencies-key :repositories :checksum :local-repo :offline? :update :mirrors :memoize-buster]) deps-result (binding [*dependencies-session* (pedantic/session project ranges overrides)] (get-dependencies-memoized dependencies-key managed-dependencies-key trimmed (apply hash-map args)))] (pedantic/do (:pedantic? project) @ranges @overrides) deps-result)) (defn- get-original-dependency "Return a match to dep (a single dependency vector) in dependencies (a dependencies vector, such as :dependencies in project.clj). Matching is done on the basis of the group/artifact id and version." [dep dependencies] (some (fn [v] ; not certain if this is the best matching fn (when (= (subvec dep 0 2) (subvec v 0 2 )) v)) dependencies)) (defn get-native-prefix "Return the :native-prefix of a dependency vector, or nil." [[id version & {:as opts}]] (get opts :native-prefix)) (defn native-dependency-info "Returns the dependency information about a dependency on the form [id version native-prefix] if the dependency is not nil." [dependency] (if dependency (let [[id version & {:as opts}] dependency] [id version (get opts :native-prefix)]))) (defn- native-dependency-map "Given a dependencies vector (such as :dependencies in project.clj) and a dependencies tree, as returned by get-dependencies, return a map from dependency identifier to :vsn, :file and :native-prefix (may be nil) for ALL dependencies this project depends on -- including transitive ones." [dependencies dependencies-tree] (let [native-dep-info (->> (map #(or (get-original-dependency % dependencies) %) (keys dependencies-tree)) (map native-dependency-info))] (->> (aether/dependency-files dependencies-tree) (#(map vector % native-dep-info)) (filter #(re-find #"\.(jar|zip)$" (.getName (first %)))) (map (fn [[file [id version native-prefix]]] [id {:file file :vsn version :native-prefix native-prefix}])) (into {})))) (defn- extract-native-dependencies "extract-native-dependencies calculates the native dependency map for all dependencies, including transitive ones. It then extracts new native content from native dependencies," [{:keys [native-path dependencies] :as project} jars dependencies-tree] ;; FIXME: This is a hack for a bug I noticed (issue #2077): Sometimes the ;; project comes through without having an init-profiles call ran on it. This ;; means that native-path is on an uninitialised form. The sane way to fix ;; this up is to check if this is the case, and if so, just ignore it. (Don't ;; worry, this call is done a ton of times) ;; To check this, just check if the path is absolute: (when (and native-path (.isAbsolute (io/file native-path))) (let [relative-native-path (utils/relativize (:root project) native-path) native-dep-map (native-dependency-map dependencies dependencies-tree) snap-deps (utils/filter-vals native-dep-map #(.endsWith (:vsn %) "SNAPSHOT")) stale-check {:dependencies (utils/map-vals native-dep-map #(select-keys % [:vsn :native-prefix])) :native-path relative-native-path}] (or (outdated-swap! project "leiningen.core.classpath.extract-native-dependencies" stale-check stale-extract-native-deps native-dep-map relative-native-path native-path) ;; Always extract native deps from SNAPSHOT deps. (doseq [[_ {:keys [native-prefix file]}] snap-deps] (extract-native-dep! native-path file native-prefix)))))) (def ^:private bootclasspath-deps (if-let [deps-file (io/resource "leiningen/bootclasspath-deps.clj")] (read-string (slurp deps-file)) {})) (defn- warn-conflicts "When using the bootclasspath (for boot speed), resources already on the bootclasspath cannot be overridden by plugins, so notify the user about it." [project dependencies] (when (#{:warn :abort} (:pedantic? project)) (let [warned (atom false)] (doseq [[artifact version] dependencies :when (and (bootclasspath-deps artifact) (not= (bootclasspath-deps artifact) version))] (reset! warned true) (warn-once "Tried to load" artifact "version" version "but" (bootclasspath-deps artifact) "was already loaded.")) (when (and @warned (not (:root project)) (not (:suppress-conflict-warnings project))) (warn-once "You can set :eval-in :subprocess in your :user profile;" "however this will increase repl load time."))))) (defn resolve-managed-dependencies "Delegate dependencies to pomegranate. This will ensure they are downloaded into ~/.m2/repository and that native components of dependencies have been extracted to :native-path. If :add-classpath? is logically true, will add the resolved dependencies to Leiningen's classpath. Supports inheriting 'managed' dependencies, e.g. to allow common dependency versions to be specified from an alternate location in the project file, or from a parent project file. Returns a seq of the dependencies' files." [dependencies-key managed-dependencies-key project & rest] (let [dependencies-tree (apply get-dependencies dependencies-key managed-dependencies-key project rest) jars (->> dependencies-tree (aether/dependency-files) (filter #(re-find #"\.(jar|zip)$" (.getName %))))] (when (some #{:add-classpath?} rest) (warn-conflicts project (concat (keys dependencies-tree) (reduce into (vals dependencies-tree))))) (when (and (= :dependencies dependencies-key) (:root project)) (extract-native-dependencies project jars dependencies-tree)) jars)) (defn ^:deprecated resolve-dependencies "Delegate dependencies to pomegranate. This will ensure they are downloaded into ~/.m2/repository and that native components of dependencies have been extracted to :native-path. If :add-classpath? is logically true, will add the resolved dependencies to Leiningen's classpath. Returns a seq of the dependencies' files. NOTE: deprecated in favor of `resolve-managed-dependencies`." [dependencies-key project & rest] (let [managed-dependencies-key (if (= dependencies-key :dependencies) :managed-dependencies)] (apply resolve-managed-dependencies dependencies-key managed-dependencies-key project rest))) (defn normalize-dep-vector "Normalize the vector for a single dependency, to ensure it is compatible with the format expected by pomegranate. The main purpose of this function is to to detect the case where the version string for a dependency has been omitted, due to the use of `:managed-dependencies`, and to inject a `nil` into the vector in the place where the version string should be." [dep] ;; Some plugins may replace a keyword with a version string later on, so ;; assume that even length vectors are alright. If not, then they will blow up ;; at a later stage. (if (even? (count dep)) dep (let [id (first dep) opts (rest dep)] ;; it's important to preserve the metadata, because it is used for ;; profile merging, etc. (with-meta (into [id nil] opts) (meta dep))))) (defn normalize-dep-vectors "Normalize the vectors for the `:dependencies` section of the project. This ensures that they are compatible with the format expected by pomegranate. The main purpose of this function is to to detect the case where the version string for a dependency has been omitted, due to the use of `:managed-dependencies`, and to inject a `nil` into the vector in the place where the version string should be." [deps] (map normalize-dep-vector deps)) (defn merge-versions-from-managed-coords [deps managed-deps] ;; NOTE: there is a new function in the 0.3.1 release of pomegranate that ;; is needed here, but was accidentally marked as private. Calling it ;; via the symbol dereference for now, but this can be changed to a ;; regular function call once https://github.com/cemerick/pomegranate/pull/74 ;; is merged. (#'aether/merge-versions-from-managed-coords (normalize-dep-vectors deps) managed-deps)) (defn managed-dependency-hierarchy "Returns a graph of the project's dependencies. Supports inheriting 'managed' dependencies, e.g. to allow common dependency versions to be specified from an alternate location in the project file, or from a parent project file." [dependencies-key managed-dependencies-key project & options] (if-let [deps-list (merge-versions-from-managed-coords (get project dependencies-key) (get project managed-dependencies-key))] (aether/dependency-hierarchy deps-list (apply get-dependencies dependencies-key managed-dependencies-key project options)))) (defn dependency-hierarchy "Returns a graph of the project's dependencies." [dependencies-key project & options] (apply managed-dependency-hierarchy dependencies-key nil project options)) (defn- normalize-path [root path] (let [f (io/file path) ; http://tinyurl.com/ab5vtqf abs (.getAbsolutePath (if (or (.isAbsolute f) (.startsWith (.getPath f) "\\")) f (io/file root path))) sep (System/getProperty "path.separator")] (str/replace abs sep (str "\\" sep)))) (defn ext-dependency? "Should the given dependency be loaded in the extensions classloader?" [dep] (second (some #(if (= :ext (first %)) dep) (partition 2 dep)))) (defn ext-classpath "Classpath of the extensions dependencies in project as a list of strings." [project] (seq (->> (filter ext-dependency? (:dependencies project)) (assoc project :dependencies) (resolve-managed-dependencies :dependencies :managed-dependencies) (map (memfn getAbsolutePath))))) (defn- visit-project! "Records a visit to a project into the volatile `seen`, returning nil if the project has already been visited." [seen {:keys [root] :as project}] (when-not (@seen root) (vswap! seen conj root) project)) (defn- project-paths "Returns a function that applies each function in checkout-paths to a given project and returns a flattened list of classpath entries." [checkout-paths] (if (seq checkout-paths) (comp flatten (apply juxt checkout-paths)) (constantly nil))) (def ^:internal ^:dynamic *seen* nil) (defn ^:internal checkout-deps-paths "Checkout dependencies are used to place source for a dependency project directly on the classpath rather than having to install the dependency and restart the dependent project." [{:keys [checkout-deps-shares root] :as project}] (require 'leiningen.core.project) (try ;; This function needs to be re-entrant as it is one of the default members of `:checkout-deps-shares`. ;; Use *seen* to communicate visit state between invocations. (binding [*seen* (or *seen* (volatile! #{root}))] ;; Visit each project and accumulate classpaths into a vector. This cannot be lazy as *seen* must be bound. (into [] (comp (keep (partial visit-project! *seen*)) (mapcat (project-paths checkout-deps-shares))) ((resolve 'leiningen.core.project/read-checkouts) project))) (catch Exception e (throw (Exception. (format "Problem loading %s checkouts" project) e))))) (defn get-classpath "Return the classpath for project as a list of strings." [project] (for [path (concat (:test-paths project) (:source-paths project) (:resource-paths project) [(:compile-path project)] (checkout-deps-paths project) (for [dep (resolve-managed-dependencies :dependencies :managed-dependencies project)] (.getAbsolutePath dep))) :when path] (normalize-path (:root project) path))) leiningen-2.9.1/leiningen-core/src/leiningen/core/eval.clj000066400000000000000000000365101343535564500235230ustar00rootroot00000000000000(ns leiningen.core.eval "Evaluate code inside the context of a project." (:require [classlojure.core :as cl] [clojure.java.io :as io] [clojure.string :as string] [cemerick.pomegranate.aether :as aether] [leiningen.core.project :as project] [leiningen.core.main :as main] [leiningen.core.classpath :as classpath] [leiningen.core.utils :as utils]) (:import (com.hypirion.io Pipe ClosingPipe) (java.io File))) (def ^:private arch-options {:x86 ["-d32"] :x86_64 ["-d64"]}) (def ^:deprecated get-os "Returns a keyword naming the host OS. Deprecated, use leiningen.core.utils/get-os instead." utils/get-os) (def ^:deprecated get-arch "Returns a keyword naming the host architecture. Deprecated, use leiningen.core.utils/get-arch instead." utils/get-arch) (def ^:deprecated platform-nullsink "Returns a file destination that will discard output. Deprecated, use leiningen.core.utils/platform-nullsink instead." utils/platform-nullsink) (def ^:dynamic *eval-print-dup* false) ;; # Preparing for eval-in-project (defn- write-pom-properties [{:keys [compile-path group name] :as project}] (when (and (:root project) (:write-pom-properties project true)) (let [path (format "%s/META-INF/maven/%s/%s/pom.properties" (or compile-path "target/classes") group name)] (utils/mkdirs (.getParentFile (io/file path))) (spit path (project/make-project-properties project))))) (defn run-prep-tasks "Execute all the prep-tasks. A task can either be a string, or a vector if it takes arguments. see :prep-tasks in sample.project.clj for examples" [{:keys [prep-tasks] :as project}] (doseq [task prep-tasks] (let [[task-name & task-args] (if (vector? task) task [task]) task-name (main/lookup-alias task-name project)] (main/apply-task task-name (dissoc project :prep-tasks) task-args)))) ;; Some tasks (defonce ^{:doc "Block on this to wait till the project is fully prepped."} prep-blocker (atom (promise))) (defn- remove-default-paths ;; Hack to get around #2010. I'm sorry =( ;; We track down metadata keys on the form :default-path/foo, then absolutize ;; foo and remove it from the list ONCE if we see it. [project paths] (let [paths-to-remove (for [k (keys (meta paths)) :when (and (keyword? k) (= "default-path" (namespace k)))] (str (io/file (:root project) (name k))))] (loop [acc [] to-remove (set paths-to-remove) [fst & rst :as ps] paths] (cond (not (seq ps)) acc (to-remove fst) (recur acc (disj to-remove fst) rst) :else (recur (conj acc fst) to-remove rst))))) (defn prep "Before we can run eval-in-project we need to prep the project by running javac, compile, and any other tasks the project specifies." [project] ;; These must exist before the project is launched. (when (:root project) (utils/mkdirs (io/file (:compile-path project "/tmp"))) ;; hack to not create default projects. For now only. (doseq [path (mapcat #(remove-default-paths project %) ((juxt :source-paths :test-paths :resource-paths) project))] (utils/mkdirs (io/file path)))) (write-pom-properties project) (classpath/resolve-managed-dependencies :dependencies :managed-dependencies project) (run-prep-tasks project) (deliver @prep-blocker true) (reset! prep-blocker (promise))) ;; # Subprocess stuff (defn native-arch-paths "Paths to the os/arch-specific directory containing native libs." [project] (let [os (:os project (utils/get-os)) arch (:arch project (utils/get-arch)) native-path (:native-path project)] (if (and os arch) (conj (->> (:dependencies project) (map classpath/get-native-prefix) (remove nil?) (map #(io/file native-path %))) (io/file native-path (name os) (name arch)))))) (defn- as-str [x] (if (instance? clojure.lang.Named x) (name x) (str x))) (defn- d-property [[k v]] (format "-D%s=%s" (as-str k) v)) (defn ^:internal get-jvm-opts-from-env [env-opts] (and (seq env-opts) (re-seq #"(?:[^\s\"']+|\"[^\"]*\"|'[^']*')+" (string/trim env-opts)))) (defn- get-jvm-args "Calculate command-line arguments for launching java subprocess." [project] (let [native-arch-paths (native-arch-paths project)] `(~(d-property [:file.encoding (or (System/getProperty "file.encoding") "UTF-8")]) ~@(get-jvm-opts-from-env (System/getenv "JVM_OPTS")) ~@(:jvm-opts project) ~@(get arch-options (:arch project)) ;; TODO: support -Xverify:none ~@(map d-property {:clojure.compile.path (:compile-path project) (str (:name project) ".version") (:version project) :clojure.debug (boolean (or (System/getenv "DEBUG") (:debug project)))}) ~@(if native-arch-paths (let [extant-paths (filter #(.exists %) native-arch-paths)] (if (seq extant-paths) [(d-property [:java.library.path (string/join java.io.File/pathSeparatorChar extant-paths)])]))) ~@(when-let [{:keys [host port non-proxy-hosts]} (classpath/get-proxy-settings)] [(d-property [:http.proxyHost host]) (d-property [:http.proxyPort port]) (d-property [:http.nonProxyHosts non-proxy-hosts])]) ~@(when-let [{:keys [host port]} (classpath/get-proxy-settings "https_proxy")] [(d-property [:https.proxyHost host]) (d-property [:https.proxyPort port])])))) (def ^:dynamic *dir* "Directory in which to start subprocesses with eval-in-project or sh." (System/getProperty "user.dir")) (def ^:dynamic *env* "Environment map with which to start subprocesses with eval-in-project or sh. Merged into the current environment unless ^:replace metadata is attached." nil) (def ^:dynamic *pump-in* "Rebind this to false to disable forwarding *in* to subprocesses." true) (def drip-env {"DRIP_INIT" nil "DRIP_INIT_CLASS" nil}) (defn- overridden-env "Returns an overridden version of the current environment as an Array of Strings of the form name=val, suitable for passing to Runtime#exec." [env] (->> (if (:replace (meta env)) env (merge {} (System/getenv) drip-env env)) (filter val) (map #(str (name (key %)) "=" (val %))) (into-array String))) (defn sh ;; TODO 3.0.0 - move to independent namespace. e.g. io.clj "A version of clojure.java.shell/sh that streams in/out/err." [& cmd] (when *pump-in* (utils/rebind-io!)) (let [env (overridden-env *env*) proc (.exec (Runtime/getRuntime) (into-array String cmd) env (io/file *dir*))] (.addShutdownHook (Runtime/getRuntime) (Thread. (fn [] (.destroy proc)))) (with-open [out (.getInputStream proc) err (.getErrorStream proc) in (.getOutputStream proc)] (let [pump-out (doto (Pipe. out System/out) .start) pump-err (doto (Pipe. err System/err) .start) ;; TODO: this prevents nrepl need-input msgs from being propagated ;; in the case of connecting to Leiningen over nREPL. pump-in (ClosingPipe. System/in in)] (when *pump-in* (.start pump-in)) (.join pump-out) (.join pump-err) (let [exit-value (.waitFor proc)] (when *pump-in* (.kill System/in) (.join pump-in) (.resurrect System/in)) exit-value))))) (defn sh-with-exit-code "Applies SH to CMD and on a non-0 exit code, throws an Exception using FAILURE-MESSAGE. A period is appended to FAILURE-MESSAGE. Returns the exit code on success. FAILURE-MESSAGE must satisfy `string?`. (first CMD) must satisfy `string?`." [failure-message & cmd] {:pre [(string? failure-message) (string? (first cmd))]} (let [exit-code (apply sh cmd)] (when-not (= 0 exit-code) (throw (Exception. (format "%s. %s exit code: %d" failure-message (first cmd) exit-code)))) exit-code)) (defn- agent-arg [coords file] (let [{:keys [options bootclasspath]} (apply hash-map coords)] (concat [(str "-javaagent:" file (and options (str "=" options)))] (if bootclasspath [(str "-Xbootclasspath/a:" file)])))) (defn ^:internal classpath-arg [project] (let [classpath-string (string/join java.io.File/pathSeparatorChar (classpath/get-classpath project)) agent-tree (classpath/get-dependencies :java-agents nil project) ;; Seems like you'd expect dependency-files to walk the whole tree ;; here, but it doesn't, which is what we want. but maybe a bug? agent-jars (aether/dependency-files (aether/dependency-hierarchy (:java-agents project) agent-tree))] `(~@(mapcat agent-arg (:java-agents project) agent-jars) ~@(if (:bootclasspath project) [(str "-Xbootclasspath/a:" classpath-string)] ["-classpath" classpath-string])))) (defn shell-command "Calculate vector of strings needed to evaluate form in a project subprocess." [project form] (let [checksum (System/getProperty "leiningen.input-checksum") init-file (if (empty? checksum) (File/createTempFile "form-init" ".clj") (io/file (:target-path project) (str checksum "-init.clj")))] (spit init-file (binding [*print-dup* *eval-print-dup*] (pr-str (when-not (System/getenv "LEIN_FAST_TRAMPOLINE") `(.deleteOnExit (File. ~(.getCanonicalPath init-file)))) form))) `(~(or (:java-cmd project) (System/getenv "JAVA_CMD") "java") ~@(classpath-arg project) ~@(get-jvm-args project) "clojure.main" "-i" ~(.getCanonicalPath init-file)))) ;; # eval-in multimethod (defmulti eval-in "Evaluate the given form in various contexts." ;; Force it to be a keyword so that we can accept symbols too. That ;; way ^:replace and ^:displace metadata can be applied. (fn [project _] (keyword (name (:eval-in project :default))))) (defmethod eval-in :default [project form] (eval-in (assoc project :eval-in :subprocess) form)) (defmethod eval-in :subprocess [project form] (binding [*dir* (:root project)] (let [exit-code (apply sh (shell-command project form))] (when (pos? exit-code) (throw (ex-info "Subprocess failed" {:exit-code exit-code})))))) (defonce trampoline-project (atom nil)) (defonce trampoline-forms (atom [])) (defonce trampoline-profiles (atom [])) (defmethod eval-in :trampoline [project form] (reset! trampoline-project project) (swap! trampoline-forms conj form) (swap! trampoline-profiles conj (select-keys project [:dependencies :source-paths :resource-paths :test-paths]))) (defmethod eval-in :classloader [project form] (when-let [classpath (map io/file (classpath/ext-classpath project))] (cl/wrap-ext-classloader classpath)) (let [classpath (map io/file (classpath/get-classpath project)) classloader (cl/classlojure classpath)] (doseq [opt (get-jvm-args project) :when (.startsWith opt "-D") :let [[_ k v] (re-find #"^-D(.*?)=(.*)$" opt)]] (if (= k "java.library.path") (cl/alter-java-library-path! (constantly (string/split v (re-pattern java.io.File/pathSeparator)))) (System/setProperty k v))) (try (cl/eval-in classloader form) (catch Exception e (println (str "Error evaluating in classloader: " (class e) ":" (.getMessage e))) (.printStackTrace e) (throw (ex-info "Classloader eval failed" {:exit-code 1})))))) (defn- send-input [message client session pending] (let [id (str (java.util.UUID/randomUUID))] (swap! pending conj id) (message client {:id id :op "stdin" :stdin (str (read-line) "\n") :session session}))) (defn- done? [{:keys [id status] :as msg} pending] (let [pending? (@pending id)] (swap! pending disj id) (and (not pending?) (some #{"done" "interrupted" "error"} status)))) (defmethod eval-in :nrepl [project form] (require 'nrepl.core) (let [port-file (io/file (:target-path project) "repl-port") connect (resolve 'nrepl/connect) client (resolve 'nrepl/client) client-session (resolve 'nrepl/client-session) message (resolve 'nrepl/message) recv (resolve 'nrepl.transport/recv)] (if (.exists port-file) (let [transport (connect :host "localhost" :port (Integer. (slurp port-file))) client (client-session (client transport Long/MAX_VALUE)) pending (atom #{})] (message client {:op "eval" :code (binding [*print-dup* *eval-print-dup*] (pr-str form))}) (doseq [{:keys [out err status session] :as msg} (repeatedly #(recv transport 100)) :while (not (done? msg pending))] (when out (print out) (flush)) (when err (binding [*out* *err*] (print err) (flush))) (when (some #{"need-input"} status) (send-input message client session pending)))) ;; TODO: warn that repl couldn't be used? (eval-in (assoc project :eval-in :subprocess) form)))) (defmethod eval-in :leiningen [project form] (when (:debug project) (System/setProperty "clojure.debug" "true")) ;; :dependencies are loaded the same way as plugins in eval-in-leiningen (project/load-plugins project :dependencies :managed-dependencies) (project/init-lein-classpath project) (doseq [opt (get-jvm-args project) :when (.startsWith opt "-D") :let [[_ k v] (re-find #"^-D(.*?)=(.*)$" opt)]] (System/setProperty k v)) (eval form)) (defmethod eval-in :pprint [project form] (require 'clojure.pprint) (println "Java:" (or (:java-cmd project) (System/getenv "JAVA_CMD") "java")) (apply println "Classpath:" (classpath-arg project)) (apply println "JVM args:" (get-jvm-args project)) ;; Can't use binding with dynamic require (let [dispatch-var (resolve 'clojure.pprint/*print-pprint-dispatch*) code-dispatch @(resolve 'clojure.pprint/code-dispatch)] (try (push-thread-bindings {dispatch-var code-dispatch}) ((resolve 'clojure.pprint/pprint) form) (finally (pop-thread-bindings))))) (defn eval-in-project "Executes form in isolation with the classpath and compile path set correctly for the project. If the form depends on any requires, put them in the init arg to avoid the Gilardi Scenario: http://technomancy.us/143" ([project form] (eval-in-project project form nil)) ([project form init] (prep project) (when (:warn-on-reflection project) (main/warn "WARNING: :warn-on-reflection is deprecated in project.clj;" "use :global-vars.")) (eval-in project `(do (set! ~'*warn-on-reflection* ~(:warn-on-reflection project)) ~@(map (fn [[k v]] `(set! ~k ~v)) (:global-vars project)) ~init ~@(:injections project) ~form)))) leiningen-2.9.1/leiningen-core/src/leiningen/core/main.clj000066400000000000000000000440311343535564500235150ustar00rootroot00000000000000(ns leiningen.core.main (:require [leiningen.core.user :as user] [leiningen.core.project :as project] [leiningen.core.classpath :as classpath] [leiningen.core.utils :as utils] [clojure.java.io :as io] [clojure.string :as string] [clojure.stacktrace :as stacktrace] [bultitude.core :as b] [cemerick.pomegranate.aether :as aether])) (def aliases {"-h" "help", "-help" "help", "--help" "help", "-?" "help", "-v" "version", "-version" "version", "--version" "version", "überjar" "uberjar", "-o" ["with-profile" "+offline"] "-U" ["with-profile" "+update"] "cp" "classpath" "halp" "help" "with-profiles" "with-profile" "readme" ["help" "readme"] "tutorial" ["help" "tutorial"] "sample" ["help" "sample"]}) ;; without a delay this loads profiles at the top-level which can ;; result in exceptions thrown outside of a nice catching context. (def ^:private profile-aliases "User profile aliases, used only when Lein is not within a project." (delay (atom (-> (user/profiles) :user :aliases)))) (defn- get-and-dissoc! "Returns a value associated with a key in a hash map contained in an atom, removing it if it exists." [atom key] (when-let [[k v] (find @atom key)] (swap! atom dissoc key) v)) (defn- merge-alias-meta [task-vector task-name] (merge (select-keys (meta task-vector) [:pass-through-help]) (meta task-name))) (defn lookup-alias "Recursively look up aliases until the task is not an alias anymore. If task-name is a vector, calls lookup-alias on the first argument and returns a partially applied task. Discards already used aliases." [task-name project & [not-found]] (if (vector? task-name) (let [[t & args] task-name ;; never mind the poor naming here. resolved-task (lookup-alias t project not-found) task-vector (if (vector? resolved-task) resolved-task [resolved-task]) merged-meta (merge-alias-meta task-vector task-name)] (-> task-vector (into args) (with-meta merged-meta))) (let [project-wo-alias (update-in project [:aliases] dissoc task-name) resolved-task (or (aliases task-name) (get (:aliases project) task-name) (when-not project (get-and-dissoc! @profile-aliases task-name)))] (cond (nil? resolved-task) (or task-name not-found "help") (= task-name resolved-task) task-name :else (recur resolved-task project-wo-alias not-found))))) (defn- lookup-task-var "Require and resolve a leiningen task from its name." [task-name] (or (utils/require-resolve (str "leiningen.plugin" task-name) task-name) (utils/require-resolve (str "leiningen." task-name) task-name))) (declare remove-alias) (defn- pass-through-help? [task-name project] (let [de-aliased (lookup-alias task-name project)] (if (vector? de-aliased) (or (:pass-through-help (meta de-aliased)) (pass-through-help? (first de-aliased) (remove-alias project task-name))) (:pass-through-help (meta (lookup-task-var de-aliased)))))) (defn task-args [[task-name & args] project] (let [pass-through? (pass-through-help? task-name project)] (if (and (= "help" (aliases (first args))) (not pass-through?)) ["help" (cons task-name (rest args))] [(lookup-alias task-name project) (vec args)]))) (defn option-arg [str] (and str (cond (.startsWith str "--") (keyword str) (.startsWith str ":") (keyword (subs str 1))))) (defn parse-options "Given a sequence of strings, return a map of command-line-esque options with keyword-ized keys and a list of additional args: (parse-options [\"--chicken\"]) => [{:--chicken true} []] (parse-options [\"--beef\" \"rare\"]) => [{:--beef \"rare\"} []] (parse-options [\":fish\" \"salmon\"]) => [{:fish \"salmon\"} []] (parse-options [\"salmon\" \"trout\"]) => [{} [\"salmon\" \"trout\"]] (parse-options [\"--to-dir\" \"test2\" \"--ham\"]) => [{:--ham true, :--to-dir \"test2\"} []] (parse-options [\"--to-dir\" \"test2\" \"--ham\" \"--\" \"pate\"]) => [{:--ham true, :--to-dir \"test2\"} [\"pate\"]]" [options] (loop [m {} [first-arg second-arg & rest :as args] options] (if-let [option (and (not= "--" first-arg) (option-arg first-arg))] (if (or (not second-arg) (option-arg second-arg)) (recur (assoc m option true) (if second-arg (cons second-arg rest) rest)) (recur (assoc m option second-arg) rest)) [m (if (= "--" first-arg) (if second-arg (cons second-arg rest) []) (or args []))]))) ;; TODO for 3.0.0: debug, info and exit should be in a separate namespace ;; (io.clj?) to avoid cyclic deps. (def ^:dynamic *debug* (System/getenv "DEBUG")) (defn debug "Print if *debug* (from DEBUG environment variable) is truthy." [& args] (when *debug* (apply println args))) (def ^:dynamic *info* (not (System/getenv "LEIN_SILENT"))) (defn info "Print if *info* (from LEIN_SILENT environment variable) is truthy." [& args] (when *info* (apply println args))) (defn warn "Print to stderr if *info* is truthy." [& args] (when *info* (binding [*out* *err*] (apply println args)))) (def ^:dynamic *exit-process?* "Bind to false to suppress process termination." true) (defn exit "Exit the process. Rebind *exit-process?* in order to suppress actual process exits for tools which may want to continue operating. Never call System/exit directly in Leiningen's own process." ([exit-code & msg] (if *exit-process?* (do (shutdown-agents) (System/exit exit-code)) (throw (ex-info (if (seq msg) (apply print-str msg) "Suppressed exit") {:exit-code exit-code :suppress-msg (empty? msg)})))) ([] (exit 0))) (defn abort "Print msg to standard err and exit with a value of 1. Will not directly exit under some circumstances; see *exit-process?*." [& msg] (binding [*out* *err*] (when (seq msg) (apply println msg)) (apply exit 1 msg))) (defn- next-dist-row [s t x pprev prev] (let [t-len (count t) eq-chars (fn [x y] (= (nth s x) (nth t (dec y))))] (reduce (fn [row y] (let [min-step (cond-> (min (inc (peek row)) ;; addition cost (inc (get prev y)) ;; deletion cost (cond-> (get prev (dec y)) ;; substitution cost (not (eq-chars x y)) inc)) (and (pos? x) (pos? (dec y)) ;; check for transposition (eq-chars x (dec y)) (eq-chars (dec x) y) (not (eq-chars x y))) (min (inc (get pprev (- y 2)))))] ;; transposition cost (conj row min-step))) [(inc x)] (range 1 (inc t-len))))) (defn- distance "Returns the Damerau–Levenshtein distance between two strings." [s t] (let [s-len (count s) t-len (count t) first-row (vec (range (inc t-len))) matrix (reduce (fn [matrix x] (conj matrix (next-dist-row s t x (peek (pop matrix)) (peek matrix)))) [[] first-row] (range s-len))] (peek (peek matrix)))) ;; workaround for #2345; need to update this list if a new task is added (def ^:private stock-tasks '[leiningen.change leiningen.check leiningen.classpath leiningen.clean leiningen.compile leiningen.deploy leiningen.deps leiningen.do leiningen.help leiningen.install leiningen.jar leiningen.javac leiningen.new leiningen.plugin leiningen.pom leiningen.release leiningen.repl leiningen.retest leiningen.run leiningen.search leiningen.show-profiles leiningen.test leiningen.trampoline leiningen.uberjar leiningen.update-in leiningen.upgrade leiningen.vcs leiningen.version leiningen.with-profile]) (defn tasks "Return a list of symbols naming all visible tasks." [] (->> (b/namespaces-on-classpath :prefix "leiningen") (into stock-tasks) (filter #(re-find #"^leiningen\.(?!core|main|util)[^\.]+$" (name %))) (distinct) (sort))) (defn suggestions "Suggest possible misspellings for task from list of tasks." [task tasks] (let [suggestions (into {} (for [t tasks :let [n (.replaceAll (name t) "leiningen." "")]] [n (distance n task)])) min (apply min (vals suggestions))] (if (<= min 3) (map first (filter #(= min (second %)) suggestions))))) (defn ^:no-project-needed task-not-found [task & _] (binding [*out* *err*] (println (str "'" task "' is not a task. See 'lein help'.")) (when-let [suggestions (suggestions task (tasks))] (println) (println "Did you mean this?") (doseq [suggestion suggestions] (println " " suggestion)))) (throw (ex-info "Task not found" {:exit-code 1 :suppress-msg true}))) (defn ^:no-project-needed function-not-found [task & _] (binding [*out* *err*] (println (str "leiningen." task " is a Clojure namespace, but not a Leiningen task."))) (throw (ex-info "Task not found" {:exit-code 1 :suppress-msg true}))) (defn- drop-partial-args "Returns a function that returns a new list of arglist, where the args provided have been taken into consideration. All arglists should start with the project argument. A special case where the arglist is on the form [& ...] will be passed through without being transformed." [pargs] (let [argcount (count pargs)] (fn [arglists] (for [[project-arg & arglist] arglists :let [[fixed-args varargs] (split-with #(not= '& %) arglist) new-fixed-args (drop argcount fixed-args)]] (if (= project-arg '&) ;; TODO: Clarify and remove this for 3.0.0 (cons project-arg arglist) (cons project-arg (concat new-fixed-args varargs))))))) (defn- splice-into-args "Alias vectors may include :project/key entries. These get replaced with the corresponding values from the project map." [project args] (into [] (for [arg args] (if (and (keyword? arg) (= (namespace arg) "project")) (project (keyword (name arg))) arg)))) (defn- partial-task [task-var pargs] (with-meta (fn [project & args] (apply task-var project (splice-into-args project (concat pargs args)))) (update-in (meta task-var) [:arglists] (drop-partial-args pargs)))) (defn resolve-task "Look up task function and perform partial application if applicable." ([task not-found] (let [[task & pargs] (if (coll? task) task [task])] (if-let [task-var (lookup-task-var task)] (partial-task task-var pargs) (not-found task)))) ([task] (resolve-task task (if (find-ns (symbol (str "leiningen." task))) #'function-not-found #'task-not-found)))) (defn ^:internal matching-arity? [task args] (some (fn [parameters] (and (if (= '& (last (butlast parameters))) (>= (count args) (- (count parameters) 3)) (= (count parameters) (inc (count args)))) parameters)) (:arglists (meta task)))) (defn- remove-alias "Removes an alias from the specified project and its metadata (which lies within :without-profiles) to avoid recursive alias calls." [project alias] (-> project (update-in [:aliases] #(if (map? %) (dissoc % alias) %)) (vary-meta update-in [:without-profiles :aliases] dissoc alias) (vary-meta update-in [:profiles] #(zipmap (keys %) (map (fn [p] (if (map? p) (remove-alias p alias) p)) (vals %)))))) (defn apply-task "Resolve task-name to a function and apply project and args if arity matches." [task-name project args] (let [[task-alias] (for [[k v] (:aliases project) :when (= v task-name)] k) project (and project (remove-alias project (or task-alias task-name))) task (resolve-task task-name)] (when-not (or (:root project) (:no-project-needed (meta task))) (abort "Couldn't find project.clj, which is needed for" task-name)) (when-not (matching-arity? task args) (abort "Wrong number of arguments to" task-name "task." "\nExpected" (string/join " or " (map (comp vec next) (:arglists (meta task)))))) (debug "Applying task" task-name "to" args) (apply task project args))) (defn resolve-and-apply "Entry point for tasks run other tasks as if they were called from the CLI." [project args] (let [[task-name args] (task-args args project)] ;; See https://github.com/technomancy/leiningen/issues/2530 ;; We can't assume the project uses the same clojure version as lein does. (binding [*print-namespace-maps* false] (apply-task task-name project args)))) (defn leiningen-version [] (or (System/getenv "LEIN_VERSION") (with-open [reader (-> "META-INF/maven/leiningen/leiningen/pom.properties" io/resource io/reader)] (-> (doto (java.util.Properties.) (.load reader)) (.getProperty "version"))))) (def ^:private exact-version-error "This project has :exact-lein-version set to \"%s\", while you have %s.") (defn versions-match? [v1 v2] (let [v1 (string/trim (first (string/split v1 #"-" 2))) v2 (string/trim (first (string/split v2 #"-" 2)))] (= v1 v2))) (defn- verify-exact-version [{:keys [exact-lein-version]}] (when-not (versions-match? exact-lein-version (leiningen-version)) (abort (format exact-version-error exact-lein-version (leiningen-version))))) (defn version-satisfies? [v1 v2] (let [v1 (map #(Integer. %) (re-seq #"\d+" (first (string/split v1 #"-" 2)))) v2 (map #(Integer. %) (re-seq #"\d+" (first (string/split v2 #"-" 2))))] (loop [versions (map vector v1 v2) [seg1 seg2] (first versions)] (cond (empty? versions) true (= seg1 seg2) (recur (rest versions) (first (rest versions))) (> seg1 seg2) true (< seg1 seg2) false)))) ;; packagers should replace this string! (def ^:private min-version-warning "*** Warning: This project requires Leiningen %s, but you have %s *** Get the latest version of Leiningen at https://leiningen.org or by executing \"lein upgrade\".") (defn- verify-min-version [{:keys [min-lein-version]}] (when-not (version-satisfies? (leiningen-version) min-lein-version) (info (format min-version-warning min-lein-version (leiningen-version))))) (defn user-agent [] (format "Leiningen/%s (Java %s; %s %s; %s)" (leiningen-version) (System/getProperty "java.vm.name") (System/getProperty "os.name") (System/getProperty "os.version") (System/getProperty "os.arch"))) (defn- configure-http "Set Java system properties controlling HTTP request behavior." [] (System/setProperty "aether.connector.userAgent" (user-agent)) (when-let [{:keys [host port non-proxy-hosts]} (classpath/get-proxy-settings)] (System/setProperty "http.proxyHost" host) (System/setProperty "http.proxyPort" (str port)) (when non-proxy-hosts (System/setProperty "http.nonProxyHosts" non-proxy-hosts))) (when-let [{:keys [host port]} (classpath/get-proxy-settings "https_proxy")] (System/setProperty "https.proxyHost" host) (System/setProperty "https.proxyPort" (str port)))) (def ^:dynamic *cwd* (System/getProperty "user.dir")) (defn default-project "Return the default project used when not in a project directory." [] (-> (project/make {:eval-in :leiningen :prep-tasks [] :source-paths ^:replace [] :resource-paths ^:replace [] :test-paths ^:replace []}) (project/init-project))) (defn- insecure-http-abort [& _] (let [repo (promise)] (reify org.apache.maven.wagon.Wagon (getRepository [this]) (setTimeout [this _]) (setInteractive [this _]) (addTransferListener [this _]) (^void connect [this ^org.apache.maven.wagon.repository.Repository the-repo ^org.apache.maven.wagon.authentication.AuthenticationInfo _ ^org.apache.maven.wagon.proxy.ProxyInfoProvider _] (deliver repo the-repo) nil) (get [this resource _] (abort "Tried to use insecure HTTP repository without TLS:\n" (str (.getId @repo) ": " (.getUrl @repo) "\n " resource) "\n" "\nThis is almost certainly a mistake; for details see" "\nhttps://github.com/technomancy/leiningen/blob/master/doc/FAQ.md"))))) (defn -main "Command-line entry point." [& raw-args] (try (project/ensure-dynamic-classloader) (aether/register-wagon-factory! "http" insecure-http-abort) (user/init) (let [project (if (.exists (io/file *cwd* "project.clj")) (project/read (str (io/file *cwd* "project.clj"))) (default-project))] (when (:exact-lein-version project) (verify-exact-version project)) (when (:min-lein-version project) (verify-min-version project)) (configure-http) (resolve-and-apply project raw-args)) (catch Exception e (if (or *debug* (not (:exit-code (ex-data e)))) (stacktrace/print-cause-trace e) (when-not (:suppress-msg (ex-data e)) (println (.getMessage e)))) (flush) (exit (:exit-code (ex-data e) 1)))) (exit 0)) leiningen-2.9.1/leiningen-core/src/leiningen/core/pedantic.clj000066400000000000000000000254141343535564500243640ustar00rootroot00000000000000(ns leiningen.core.pedantic "This namespace exists to hook into Aether's dependency resolution and provide feedback about the dependency tree. Using a `DependencyGraphTransformer` allows us to look at the tree both before and after conflict resolution so that downloading all of the dependencies only occurs once. Aether uses a `NearestVersionConflictResolver` to resolve which versions to use in case of a conflict. The `NearestVersionConflictResolver` uses a `ConflictIdSorter` to determine those, and it will save the information in `SORTED_CONFLICT_IDS` and `CONFLICT_IDS`. We can similarly use the conflict information to determine which version is choosen in a conflict. Additional important classes from Aether: * `DependencyGraphTransformationContext` * `DependencyNode` * `Dependency` * `Artifact` * `Version` * `VersionConstraint`" (:refer-clojure :exclude [do]) (:require [cemerick.pomegranate.aether :as aether]) (:import (org.eclipse.aether.graph Exclusion) (org.eclipse.aether.collection DependencyGraphTransformer) (org.eclipse.aether.util.graph.transformer TransformationContextKeys ConflictIdSorter))) ;; This namespace originated as an independent library which was at ;; https://github.com/xeqi/pedantic in order to allow it to evolve ;; at its own pace decoupled from Leiningen's release cycle, but now it's ;; part of Leiningen as of 2.8.0. (defn- initialize-conflict-ids! "Make sure that `SORTED_CONFLICT_IDS` and `CONFLICT_IDS` have been initialized. Similar to what a NearestVersionConflictResolver will do." [node context] (when-not (.get context TransformationContextKeys/SORTED_CONFLICT_IDS) (-> (ConflictIdSorter.) (.transformGraph node context)))) (defn- range? "Does the path point to a DependencyNode asking for a version range?" [{:keys [node]}] (when-let [vc (.getVersionConstraint node)] (not (nil? (.getRange vc))))) (defn- set-ranges! "Set ranges to contain all paths that asks for a version range" [ranges paths] (reset! ranges (doall (filter range? paths)))) (defn- node< "Is the version of node1 < version of node2." [node1 node2] (< (compare (.getVersion node1) (.getVersion node2)) 0)) (defn- node->artifact-map [node] (if-let [d (.getDependency node)] (if-let [a (.getArtifact d)] (let [b (bean a)] (-> b (select-keys [:artifactId :groupId :exclusions :version :extension :properties]) (update-in [:exclusions] vec)))))) (defn- node= "Check value equality instead of reference equality." [n1 n2] (= (node->artifact-map n1) (node->artifact-map n2))) (defn- top-level? "Is the path a top level dependency in the project?" [{:keys [parents]}] ;; Parent is root node (= 1 (count parents))) (defn- set-overrides! "Check each `accepted-path` against its conflicting paths. If a conflicting path fails the pedantic criteria then add information representing this possibly confusing situation to `overrides`." [overrides conflicts accepted-paths ranges] (doseq [{:keys [node parents] :as path} accepted-paths] (let [ignoreds (for [conflict-path (conflicts node) :when (and (not= path conflict-path) ;; This is the pedantic criteria (or (node< node (:node conflict-path)) (top-level? conflict-path)))] conflict-path)] (when (not (empty? ignoreds)) (swap! overrides conj {:accepted path :ignoreds ignoreds :ranges (filter #(node= (:node %) node) ranges)}))))) (defn- all-paths "Breadth first traversal of the graph from DependencyNode node. Short circuits a path when a cycle is detected." [node] (loop [paths [{:node node :parents []}] results []] (if (empty? paths) results (recur (for [{:keys [node parents]} paths :when (not (some #{node} parents)) c (.getChildren node)] {:node c :parents (conj parents node)}) (doall (concat results paths)))))) (defn- transform-graph "Examine the tree with root `node` for version ranges, then allow the original `transformer` to perform resolution, then check for overriden dependencies." [ranges overrides node context transformer] ;; Force initialization of the context like NearestVersionConflictResolver (initialize-conflict-ids! node context) ;; Get all the paths of the graph before dependency resolution (let [potential-paths (all-paths node)] (set-ranges! ranges potential-paths) (.transformGraph transformer node context) ;; The original transformer should have done dependency resolution, ;; so now we can gather just the accepted paths and use the ConflictId ;; to match against the potential paths (let [node->id (.get context TransformationContextKeys/CONFLICT_IDS) id->paths (reduce (fn [acc {:keys [node] :as path}] (update-in acc [(.get node->id node)] conj path)) {} ;; Remove ranges as they cause problems and were ;; warned above (remove range? potential-paths))] (set-overrides! overrides #(->> % (.get node->id) id->paths) (all-paths node) @ranges)))) (defn- use-transformer "Wrap the session's current `DependencyGraphTransformer` with one that checks for version ranges and overriden dependencies. `ranges` and `overrides` are expect to be (atom []). This provides a way to send back information since the return value can't be used here. After resolution: `ranges` will be a vector of paths (see pedantic.path) `overrides` will be a vector of maps with keys [:accepted :ignoreds :ranges]. `:accepted` is the path that was resolved. :ignored is a list of paths that were not used. `:ranges` is a list of paths containing version ranges that might have affected the resolution." [session ranges overrides] (let [transformer (.getDependencyGraphTransformer session)] (.setDependencyGraphTransformer session (reify DependencyGraphTransformer (transformGraph [_ node context] (transform-graph ranges overrides node context transformer) ;;Return the DependencyNode in order to meet ;;transformGraph's contract node))))) (defn ^:internal session [project ranges overrides] (if (:pedantic? project) #(-> % aether/repository-session (use-transformer ranges overrides)))) (defn- group-artifact [artifact] (if (= (.getGroupId artifact) (.getArtifactId artifact)) (.getGroupId artifact) (str (.getGroupId artifact) "/" (.getArtifactId artifact)))) (defn- dependency-str [dependency & [version]] (if-let [artifact (and dependency (.getArtifact dependency))] (str "[" (group-artifact artifact) " \"" (or version (.getVersion artifact)) "\"" (if-let [classifier (.getClassifier artifact)] (if (not (empty? classifier)) (str " :classifier \"" classifier "\""))) (if-let [extension (.getExtension artifact)] (if (not= extension "jar") (str " :extension \"" extension "\""))) (if-let [exclusions (seq (.getExclusions dependency))] (str " :exclusions " (mapv (comp symbol group-artifact) exclusions))) "]"))) (defn- message-for [path & [show-constraint?]] (->> path (map #(dependency-str (.getDependency %) (.getVersionConstraint %))) (remove nil?) (interpose " -> ") (apply str))) (defn- message-for-version [{:keys [node parents]}] (message-for (conj parents node))) (defn- exclusion-for-range [node parents] (if-let [top-level (second parents)] (let [excluded-artifact (.getArtifact (.getDependency node)) exclusion (Exclusion. (.getGroupId excluded-artifact) (.getArtifactId excluded-artifact) "*" "*") exclusion-set (into #{exclusion} (.getExclusions (.getDependency top-level))) with-exclusion (.setExclusions (.getDependency top-level) exclusion-set)] (dependency-str with-exclusion)) "")) (defn- message-for-range [{:keys [node parents]}] (str (message-for (conj parents node) :constraints) "\n" "Consider using " (exclusion-for-range node parents) ".")) (defn- exclusion-for-override [{:keys [node parents]}] (exclusion-for-range node parents)) (defn- message-for-override [{:keys [accepted ignoreds ranges]}] {:accepted (message-for-version accepted) :ignoreds (map message-for-version ignoreds) :ranges (map message-for-range ranges) :exclusions (map exclusion-for-override ignoreds)}) (defn- warn [& args] ;; TODO: remove me once #1227 is merged (require 'leiningen.core.main) (apply (resolve 'leiningen.core.main/warn) args)) (def ^:private warn-once (memoize warn)) (defn- pedantic-print-ranges [messages] (when-not (empty? messages) (warn "WARNING!!! version ranges found for:") (doseq [dep-string messages] (warn dep-string)) (warn))) (defn- pedantic-print-overrides [messages] (when-not (empty? messages) (warn "Possibly confusing dependencies found:") (doseq [{:keys [accepted ignoreds ranges exclusions]} messages] (warn accepted) (warn " overrides") (doseq [ignored (interpose " and" ignoreds)] (warn ignored)) (when-not (empty? ranges) (warn " possibly due to a version range in") (doseq [r ranges] (warn r))) (warn "\nConsider using these exclusions:") (doseq [ex (distinct exclusions)] (warn ex)) (warn)))) (alter-var-root #'pedantic-print-ranges memoize) (alter-var-root #'pedantic-print-overrides memoize) (defn ^:internal do [pedantic-setting ranges overrides] ;; Need to turn everything into a string before calling ;; pedantic-print-*, otherwise we can't memoize due to bad equality ;; semantics on aether GraphEdge objects. (let [key (keyword pedantic-setting) abort-or-true (#{true :abort} key)] (when (and key (not= key :overrides)) (pedantic-print-ranges (distinct (map message-for-range ranges)))) (when (and key (not= key :ranges)) (pedantic-print-overrides (map message-for-override overrides))) (when (and abort-or-true (not (empty? (concat ranges overrides)))) (require 'leiningen.core.main) ((resolve 'leiningen.core.main/abort) ; cyclic dependency =\ "Aborting due to :pedantic? :abort")))) leiningen-2.9.1/leiningen-core/src/leiningen/core/project.clj000066400000000000000000001212601343535564500242370ustar00rootroot00000000000000(ns leiningen.core.project "Read project.clj files." (:refer-clojure :exclude [read]) (:require [clojure.walk :as walk] [clojure.java.io :as io] [clojure.set :as set] [cemerick.pomegranate :as pomegranate] [cemerick.pomegranate.aether :as aether] [leiningen.core.utils :as utils] [leiningen.core.user :as user] [leiningen.core.classpath :as classpath] [clojure.string :as str]) (:import (clojure.lang DynamicClassLoader) (java.io PushbackReader Reader File) (java.util.regex Pattern))) (defn make-project-properties [project] (with-open [baos (java.io.ByteArrayOutputStream.)] (let [properties (doto (java.util.Properties.) (.setProperty "version" (:version project)) (.setProperty "groupId" (:group project)) (.setProperty "artifactId" (:name project))) git-head (utils/resolve-git-dir project)] (when (.exists git-head) (if-let [revision (utils/read-git-head git-head)] (.setProperty properties "revision" revision))) (.store properties baos "Leiningen")) (str baos))) (defn- warn [& args] ;; TODO: remove with 3.0.0 (require 'leiningen.core.main) (apply (resolve 'leiningen.core.main/warn) args)) (def ^:private warn-once (memoize warn)) (defn- update-each-contained [m keys f & args] (reduce (fn [m k] (if (contains? m k) (apply update m k f args) m)) m keys)) (defn- update-first [coll pred f] (let [[pre [existing & post]] (split-with (complement pred) coll)] (concat pre [(f existing)] post))) ;; # Project definition and normalization (defn composite-profile? "Returns true if the profile is composite, false otherwise." [profile] (vector? profile)) (defn group-id [id] (if (string? id) (first (str/split id #"/")) (or (namespace id) (name id)))) (defn artifact-id [id] (if (string? id) (last (str/split id #"/")) (name id))) (defn artifact-map [id] {:artifact-id (artifact-id id) :group-id (group-id id)}) (defn exclusion-map "Transform an exclusion vector into a map that is easier to combine with meta-merge. This allows a profile to override specific exclusion options." [spec] (if-let [[id & {:as opts}] (if (symbol? spec) [spec] spec)] (-> opts (merge (artifact-map id)) (with-meta (meta spec))))) (defn exclusion-vec "Transform an exclusion map back into a vector of the form: [name/group & opts]" [exclusion] (if-let [{:keys [artifact-id group-id]} exclusion] (into [(symbol group-id artifact-id)] (apply concat (dissoc exclusion :artifact-id :group-id))))) (defn dependency-map "Transform a dependency vector into a map that is easier to combine with meta-merge. This allows a profile to override specific dependency options." [dep] (if-let [[id version & {:as opts}] (classpath/normalize-dep-vector dep)] (-> opts (merge (artifact-map id)) (assoc :version version) (update-each-contained [:exclusions] (partial map exclusion-map)) (with-meta (meta dep))))) (defn dependency-vec "Transform a dependency map back into a vector of the form: [name/group \"version\" & opts]" [dep] (if-let [{:keys [artifact-id group-id version]} dep] (-> dep (update-each-contained [:exclusions] (partial map exclusion-vec)) (update-each-contained [:exclusions] distinct) (dissoc :artifact-id :group-id :version) (->> (apply concat) (into [(symbol group-id artifact-id) version])) (with-meta (meta dep))))) (defn- meta* "Returns the metadata of an object, or nil if the object cannot hold metadata." [obj] (if (instance? clojure.lang.IObj obj) (meta obj) nil)) (defn- with-meta* "Returns an object of the same type and value as obj, with map m as its metadata if the object can hold metadata." [obj m] (if (instance? clojure.lang.IObj obj) (with-meta obj m) obj)) (defn- vary-meta* "Returns an object of the same type and value as obj, with (apply f (meta obj) args) as its metadata, if the object can hold metadata." [obj f & args] (if (instance? clojure.lang.IObj obj) (apply vary-meta obj f args) obj)) (defn- displace? "Returns true if the object is marked as displaceable" [obj] (-> obj meta* :displace)) (defn- replace? "Returns true if the object is marked as replaceable" [obj] (-> obj meta* :replace)) (defn- top-displace? "Returns true if the object is marked as top-displaceable" [obj] (-> obj meta* :top-displace)) (defn- different-priority? "Returns true if either left has a higher priority than right or vice versa." [left right] (boolean (or (some (some-fn nil? displace? replace?) [left right]) (top-displace? left)))) (defn- remove-top-displace [obj] (if-not (top-displace? obj) obj (vary-meta obj dissoc :top-displace))) (defn- pick-prioritized "Picks the highest prioritized element of left and right and merge their metadata." [left right] (cond (nil? left) right (nil? right) (remove-top-displace left) ;; TODO: support :reverse? (top-displace? left) right (and (displace? left) (top-displace? right)) left (and (displace? left) ;; Pick the rightmost (displace? right)) ;; if both are marked as displaceable (with-meta* right (merge (meta* left) (meta* right))) (and (replace? left) ;; Pick the rightmost (replace? right)) ;; if both are marked as replaceable (with-meta* right (merge (meta* left) (meta* right))) (or (displace? left) (replace? right)) (with-meta* right (merge (-> left meta* (dissoc :displace)) (-> right meta* (dissoc :replace)))) (or (replace? left) (displace? right)) (with-meta* left (merge (-> right meta* (dissoc :displace)) (-> left meta* (dissoc :replace)))))) (declare meta-merge) ;; TODO: drop this and use read-eval syntax in 3.0 (defn- unquote-project "Inside defproject forms, unquoting (~) allows for arbitrary evaluation." [args] (walk/walk (fn [item] (cond (and (seq? item) (= `unquote (first item))) (second item) ;; needed if we want fn literals preserved (or (seq? item) (symbol? item)) (list 'quote item) :else (let [result (unquote-project item)] ;; clojure.walk strips metadata (if-let [m (meta item)] (with-meta result m) result)))) identity args)) (def defaults ;; TODO: move :repositories here in 3.0 {:source-paths ^:top-displace ^:default-path/src ["src"] :resource-paths ^:top-displace ^:default-path/resources ["resources"] :test-paths ^:top-displace ^:default-path/test ["test"] :native-path "%s/native" :compile-path "%s/classes" :target-path "target" :clean-targets ^:top-displace [:target-path] ;; TODO: remove :top-displace for :prep-tasks in 3.0 :prep-tasks ^:top-displace ["javac" "compile"] ;; If these change, be sure to update release docstring and DEPLOY.md :release-tasks ^:top-displace [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] ["vcs" "tag"] ["deploy"] ["change" "version" "leiningen.release/bump-version"] ["vcs" "commit"] ["vcs" "push"]] :pedantic? (quote ^:top-displace ranges) :jar-exclusions [#"^\." (re-pattern (Pattern/quote (str File/separator ".")))] :eval-in :default :offline? (not (nil? (System/getenv "LEIN_OFFLINE"))) :uberjar-exclusions [#"(?i)^META-INF/[^/]*\.(SF|RSA|DSA)$"] :uberjar-merge-with {"META-INF/plexus/components.xml" 'leiningen.uberjar/components-merger, "data_readers.clj" 'leiningen.uberjar/clj-map-merger, ;; So we don't break Java's ServiceLoader mechanism ;; during uberjar construction #"META-INF/services/.*" `[slurp #(str %1 "\n" %2) spit]} :global-vars {}}) (defn dep-key "The unique key used to dedupe dependencies." [dep] (-> (dependency-map dep) (select-keys [:group-id :artifact-id :classifier :extension]))) (defn- reduce-dep-step [deps dep] (let [k (dep-key dep)] (update-first deps #(= k (dep-key %)) (fn [existing] (dependency-vec (meta-merge (dependency-map existing) (dependency-map dep))))))) (defn normalize-aot [project] (if (= :all (:aot project)) (assoc project :aot ^:replace [:all]) project)) (defn- normalize-repo "Normalizes a repository to the canonical repository form." [[id opts :as repo]] (with-meta [id (if (string? opts) {:url opts} opts)] (meta repo))) (defn- normalize-repos "Normalizes a vector of repositories to the canonical repository form." [repos] (with-meta (mapv normalize-repo repos) (meta repos))) (defn- reduce-repo-step [repos [id opts :as repo]] (update-first repos #(= id (first %)) (fn [[_ existing :as original]] (let [opts (if (keyword? opts) (-> (filter #(= (first %) (name opts)) repos) first second) opts) repo (with-meta [id opts] (meta repo))] (if (different-priority? repo original) (pick-prioritized repo original) (with-meta [id (meta-merge existing opts)] (merge (meta original) (meta repo)))))))) (def empty-dependencies (with-meta [] {:reduce reduce-dep-step})) (def empty-repositories (with-meta [] {:reduce reduce-repo-step})) (def empty-paths (with-meta [] {:prepend true})) (def default-repositories (with-meta [["central" {:url "https://repo1.maven.org/maven2/" :snapshots false}] ["clojars" {:url "https://repo.clojars.org/"}]] {:reduce reduce-repo-step})) (def deploy-repositories (with-meta [["clojars" {:url "https://clojars.org/repo/" :password :gpg :username :gpg}]] {:reduce reduce-repo-step})) (defn- mark-with-replace [obj] (vary-meta* obj assoc :replace true)) (defn normalize-values "Transform values within a project or profile map to normalized values, such that internal functions can assume that the values are already normalized." [map] (-> map (update-each-contained [:repositories :deploy-repositories :mirrors :plugin-repositories] normalize-repos) (update-each-contained [:profiles] utils/map-vals normalize-values) (update-each-contained [:aliases] utils/map-vals mark-with-replace) (normalize-aot))) (def ^:private empty-meta-merge-defaults {:repositories empty-repositories :plugin-repositories empty-repositories :deploy-repositories deploy-repositories :plugins empty-dependencies :dependencies empty-dependencies :source-paths empty-paths :resource-paths empty-paths :test-paths empty-paths}) (defn- setup-map-defaults "Transform a project or profile map by merging empty default values containing reducing functions and other metadata properties, replacing aliases and normalizing values inside the map." [raw-map empty-defaults] (with-meta (merge-with (fn [left right] ;; Assumes that left always contains :reduce OR :prepend in its meta (with-meta (cond (different-priority? left right) (pick-prioritized left right) (-> left meta :reduce) (-> left meta :reduce (reduce left right)) (-> left meta :prepend) (concat right left)) (merge (meta left) (dissoc (meta right) :top-displace)))) empty-defaults (-> raw-map (assoc :jvm-opts (or (:jvm-opts raw-map) (:java-opts raw-map))) (assoc :eval-in (or (:eval-in raw-map) (if (:eval-in-leiningen raw-map) :leiningen))) (dissoc :eval-in-leiningen :java-opts) (normalize-values))) (meta raw-map))) (defn- with-normalized-deps [profile] (let [deps (:dependencies profile)] (assoc profile :dependencies (with-meta (classpath/normalize-dep-vectors deps) (meta deps))))) (defn- setup-profile-with-empty "Setup a profile map with empty defaults." [raw-profile] (if (composite-profile? raw-profile) ;; TODO: drop support for partially-composite profiles in 3.0 (with-meta (mapv #(cond-> % (composite-profile? %) setup-profile-with-empty) raw-profile) (meta raw-profile)) (let [empty-defaults (select-keys empty-meta-merge-defaults (keys raw-profile))] (setup-map-defaults (with-normalized-deps raw-profile) empty-defaults)))) (defn- setup-map-of-profiles "Setup a map of profile maps with empty defaults." [map-of-profiles] (utils/map-vals map-of-profiles setup-profile-with-empty)) (defn make ([project project-name version root] (make (with-meta (assoc project :name (name project-name) :group (or (namespace project-name) (name project-name)) :version version :root root) (meta project)))) ([project] (let [repos (if (:omit-default-repositories project) (do (warn-once "WARNING:" ":omit-default-repositories is deprecated;" "use :repositories ^:replace [...] instead.") empty-repositories) default-repositories)] (setup-map-defaults (-> (meta-merge defaults project) (dissoc :eval-in-leiningen :omit-default-repositories) (assoc :eval-in (or (:eval-in project) (if (:eval-in-leiningen project) :leiningen, :subprocess))) (update-each-contained [:profiles] setup-map-of-profiles) (with-meta (meta project))) (assoc empty-meta-merge-defaults :repositories repos :plugin-repositories repos))))) (defn- argument-list->argument-map [args] (let [keys (map first (partition 2 args)) unique-keys (set keys)] (if (= (count keys) (count unique-keys)) (apply hash-map args) (let [duplicates (->> (frequencies keys) (remove #(> 2 (val %))) (map first))] (throw (IllegalArgumentException. (format "Duplicate keys: %s" (clojure.string/join ", " duplicates)))))))) (defmacro defproject "The project.clj file must either def a project map or call this macro. See `lein help sample` to see what arguments it accepts." [project-name version & args] (let [f (io/file *file*)] `(let [args# ~(unquote-project (argument-list->argument-map args)) root# ~(if f (.getParent f))] (def ~'project (make args# '~project-name ~version root#))))) (defn- add-exclusions [exclusions dep] (dependency-vec (update-in (dependency-map dep) [:exclusions] into (map exclusion-map exclusions)))) (defn- add-global-exclusions [project] (let [{:keys [dependencies exclusions]} project] (if-let [exclusions (and (seq dependencies) (seq exclusions))] (assoc project :dependencies (with-meta (mapv (partial add-exclusions exclusions) dependencies) (meta dependencies))) project))) (defn- absolutize [root path] (str (if (.isAbsolute (io/file path)) path (io/file root path)))) (defn- absolutize-path [{:keys [root] :as project} key] (cond (re-find #"-path$" (name key)) (update project key (partial absolutize root)) (re-find #"-paths$" (name key)) (update project key #(with-meta* (map (partial absolutize root) %) (meta %))) :else project)) (defn absolutize-paths [project] (reduce absolutize-path project (keys project))) (defn- sha1 [content] (.toString (BigInteger. 1 (-> (java.security.MessageDigest/getInstance "SHA1") (.digest (.getBytes content)))) 16)) (defn- keyword-composite-profile? [profile] (and (composite-profile? profile) (every? keyword? profile))) (defn- ordered-keyword-composite-profiles [project] (->> project meta :profiles (filter (comp keyword-composite-profile? val)) (remove (comp empty? val)) (sort-by count) (reverse))) (defn- first-matching-composite [profiles composites] (->> composites (filter (fn [[_ v]] (= v (take (count v) profiles)))) (first))) (defn- normalize-profile-names [project profiles] (let [composites (ordered-keyword-composite-profiles project)] (loop [profiles' profiles normalized ()] (if (seq profiles') (if-let [[k v] (first-matching-composite profiles' composites)] (recur (drop (count v) profiles') (cons k normalized)) (recur (rest profiles') (cons (first profiles') normalized))) (if (= (count profiles) (count normalized)) profiles (normalize-profile-names project (reverse normalized))))))) (defn profile-scope-target-path [project profiles] (let [n #(if (map? %) (subs (sha1 (pr-str %)) 0 8) (name %))] (if (:target-path project) (update-in project [:target-path] format (str/join "+" (map n (normalize-profile-names project profiles)))) project))) (defn target-path-subdirs [{:keys [target-path] :as project} key] (if (project key) (update-in project [key] format target-path) project)) ;; # Profiles: basic merge logic (def ^:private hooke-injection (with-open [rdr (-> "robert/hooke.clj" io/resource io/reader PushbackReader.)] `(do (ns ~'leiningen.core.injected) ~@(doall (take-while #(not= % ::eof) (rest (repeatedly #(clojure.core/read rdr false ::eof))))) (ns ~'user)))) ;; users of old JVMs will have to set LEIN_JVM_OPTS to turn off tiered ;; compilation, so if they've done that we should do the same for project JVMs (def tiered-jvm-opts (if (.contains (or (System/getenv "LEIN_JVM_OPTS") "") "Tiered") ["-XX:+TieredCompilation" "-XX:TieredStopAtLevel=1"])) (def default-jvm-opts [;; actually does the opposite; omits trace unless this is set "-XX:-OmitStackTraceInFastThrow"]) (def default-profiles "Profiles get merged into the project map. The :dev, :provided, and :user profiles are active by default." (atom {:default [:leiningen/default] :leiningen/default [:base :system :user :provided :dev] :base {:resource-paths ^:default-path/dev-resources ["dev-resources"] :jvm-opts (with-meta `[~@default-jvm-opts ~@tiered-jvm-opts] {:displace true}) :test-selectors {:default (with-meta '(constantly true) {:displace true})} ;; bump deps in leiningen's own project.clj with these :dependencies '[^:displace [nrepl/nrepl "0.6.0" :exclusions [org.clojure/clojure]] ^:displace [clojure-complete "0.2.5" :exclusions [org.clojure/clojure]]] :checkout-deps-shares [:source-paths :test-paths :resource-paths :compile-path #'classpath/checkout-deps-paths] :aliases {"downgrade" "upgrade"}} :leiningen/test {:injections [hooke-injection] :test-selectors {:default (with-meta '(constantly true) {:displace true})}} :uberjar {} ; TODO: use :aot :all here in 3.0 :update {:update :always} :offline {:offline? true} :debug {:debug true}})) (def default-profile-metadata {:dev {:pom-scope :test} :test {:pom-scope :test} :uberjar {:leaky true} :provided {:pom-scope :provided} :repl {:repl true}}) (defn- meta-merge "Recursively merge values based on the information in their metadata." [left right] (cond (different-priority? left right) (pick-prioritized left right) (-> left meta :reduce) (-> left meta :reduce (reduce left right) (with-meta (meta left))) (and (map? left) (map? right)) (merge-with meta-merge left right) (and (set? left) (set? right)) (set/union right left) (and (coll? left) (coll? right)) (if (or (-> left meta :prepend) (-> right meta :prepend)) (-> (concat right left) (with-meta (merge (meta right) (meta left)))) (concat left right)) (= (class left) (class right)) right :else (do (warn left "and" right "have a type mismatch merging profiles.") right))) (defn- apply-profiles [project profiles] (reduce (fn [project profile] (with-meta (meta-merge project profile) (meta-merge (meta project) (meta profile)))) project profiles)) (defn- lookup-profile* "Lookup a profile in the given profiles map, warning when the profile doesn't exist. Recurse whenever a keyword or vector is found, combining all profiles in the vector." [profiles profile] (cond (keyword? profile) (let [result (get profiles profile)] (when-not (or result (#{:provided :dev :user :test :base :default :production :system :repl} profile)) (warn "Warning: profile" profile "not found.")) (lookup-profile* profiles result)) (composite-profile? profile) (apply-profiles {} (map (partial lookup-profile* profiles) profile)) :else (or profile {}))) (defn- lookup-profile "Equivalent with lookup-profile*, except that it will attach the profile name as an active profile in the profile metadata if the profile is a keyword." [profiles profile] (cond-> (lookup-profile* profiles profile) (keyword? profile) (vary-meta update-in [:active-profiles] (fnil conj []) profile))) (defn- expand-profile* [profiles profile-meta profile] (let [content (or (get profiles profile) (get @default-profiles profile))] ;; TODO: drop "support" for partially-composite profiles in 3.0 (if (or (nil? content) (map? content) (and (sequential? content) (some map? content))) [[profile profile-meta]] (mapcat (partial expand-profile* profiles (merge profile-meta (meta content))) (if (sequential? content) content [content]))))) (defn expand-profile-with-meta "Recursively expand the keyword `profile` in `project` to a sequence of vectors of atomic (non-composite) profile keywords and their inherited metadata." [project profile] (expand-profile* (:profiles (meta project)) nil profile)) (defn expand-profiles-with-meta "Recursively expand a collection of profiles" [project profiles] (mapcat (partial expand-profile-with-meta project) profiles)) (defn expand-profile "Recursively expand the keyword `profile` in `project` to a sequence of atomic (non-composite) profile keywords." [project profile] (->> (expand-profile* (:profiles (meta project)) nil profile) (map first))) (defn expand-profiles "Recursively expand a collection of profiles" [project profiles] (mapcat (partial expand-profile project) profiles)) (defn- warn-user-repos [profiles] (let [has-url? (fn [entry] (or (string? entry) (:url entry))) repo-profiles (filter #(->> (second %) :repositories (map second) (some has-url?)) profiles)] (when (and (seq repo-profiles) (not (System/getenv "LEIN_SUPPRESS_USER_LEVEL_REPO_WARNINGS"))) (warn-once ":repositories detected in user-level profiles!" (vec (map first repo-profiles)) "\nSee" "https://github.com/technomancy/leiningen/wiki/Repeatability")))) (defn- warn-user-profile [root profiles] (when (and root (contains? profiles :user)) (warn-once "WARNING: user-level profile defined in project files."))) (defn- system-profiles [] (let [sys-profile-dir (if (= :windows (utils/get-os)) (io/file (System/getenv "AllUsersProfile") "Leiningen") (io/file "/etc" "leiningen"))] (user/load-profiles sys-profile-dir))) (defn ^:internal project-profiles [project] (let [profiles (utils/read-file (io/file (:root project) "profiles.clj"))] (warn-user-profile (:root project) profiles) profiles)) (defn read-profiles "Read profiles from a variety of sources. We check Leiningen's defaults, system-level profiles (usually in /etc), the profiles.clj file in ~/.lein, the profiles.clj file in the project root, and the :profiles key from the project map." [project] ;; TODO: All profile reads (load-profiles and profiles, notable) should wrap ;; setup-profiles instead of doing stuff here, but as it is a cyclic ;; dependency, defer it to 3.0. Although I guess we don't need this ;; functionality for 3.0 if we're smart. (let [sys-profiles (setup-map-of-profiles (system-profiles)) user-profiles (setup-map-of-profiles (user/profiles)) proj-profiles-file (setup-map-of-profiles (project-profiles project))] (warn-user-repos (concat user-profiles sys-profiles)) (warn-user-profile (:root project) (:profiles project)) (merge @default-profiles sys-profiles user-profiles (:profiles project) proj-profiles-file))) (defn- scope-plugin-profile [local-name plugin-name] (keyword (str "plugin." plugin-name) (name local-name))) (defn- read-plugin-profiles [project] (let [p (for [[plugin version] (:plugins project) :let [profiles (io/resource (format "%s/profiles.clj" (name plugin)))] :when profiles] (for [[local-name profile] (read-string (slurp profiles))] [(scope-plugin-profile local-name (name plugin)) profile]))] (into {} (apply concat p)))) ;; # Lower-level profile plumbing: loading plugins, hooks, middleware, certs (defn ensure-dynamic-classloader [] (let [thread (Thread/currentThread) cl (.getContextClassLoader thread)] (when-not (instance? DynamicClassLoader cl) (.setContextClassLoader thread (DynamicClassLoader. cl))))) (def ^:private registered-wagon-files (atom #{})) (defn load-plugins ([project dependencies-key managed-dependencies-key] (when (seq (get project dependencies-key)) (let [repos-project (update-in project [:repositories] meta-merge (:plugin-repositories project))] (classpath/resolve-managed-dependencies dependencies-key managed-dependencies-key repos-project :add-classpath? true))) (doseq [wagon-file (-> (.getContextClassLoader (Thread/currentThread)) (.getResources "leiningen/wagons.clj") (enumeration-seq)) :when (not (@registered-wagon-files wagon-file)) [hint factory] (read-string (slurp wagon-file))] (aether/register-wagon-factory! hint (eval factory)) (swap! registered-wagon-files conj wagon-file)) project) ([project dependencies-key] (load-plugins project dependencies-key nil)) ([project] (load-plugins project :plugins))) (defn plugin-vars [project type] (for [[plugin _ & {:as opts}] (:plugins project) :when (get opts type true)] (-> (symbol (str (name plugin) ".plugin") (name type)) (with-meta {:optional true})))) (defn- plugin-hooks [project] (plugin-vars project :hooks)) (defn- plugin-middleware [project] (plugin-vars project :middleware)) (defn- load-hook [hook-name] (if-let [hook (try (utils/require-resolve hook-name) (catch Exception e (utils/error "problem requiring" hook-name "hook") (throw e)))] (try (warn-once "Warning: implicit hook found:" hook-name "\nHooks are deprecated and will be removed" "in a future version.") (hook) (catch Exception e (utils/error "problem activating" hook-name "hook") (throw e))) (when-not (:optional (meta hook-name)) (utils/error "cannot resolve" hook-name "hook")))) (defn load-hooks [project & [ignore-missing?]] (when (and (:implicits project true) (:implicit-hooks project true)) (doseq [hook-name (concat (plugin-hooks project) (:hooks project))] ;; if hook-name is just a namespace assume hook fn is called activate (let [hook-name (if (namespace hook-name) hook-name (symbol (name hook-name) "activate"))] (load-hook hook-name)))) project) (defn apply-middleware ([project] (reduce apply-middleware project (concat (plugin-middleware project) (:middleware project)))) ([project middleware-name] (if (and (:implicits project true) (:implicit-middleware project true)) (if-let [middleware (utils/require-resolve middleware-name)] (middleware project) (do (when-not (:optional (meta middleware-name)) (utils/error "cannot resolve" middleware-name "middleware")) project)) project))) (defn load-certificates "Load the SSL certificates specified by the project and register them for use by Aether." [project] (when (seq (:certificates project)) ;; lazy-loading might give a launch speed boost here (require 'leiningen.core.ssl) (let [make-context (resolve 'leiningen.core.ssl/make-sslcontext) read-certs (resolve 'leiningen.core.ssl/read-certs) default-certs (resolve 'leiningen.core.ssl/default-trusted-certs) override-wagon-registry! (resolve 'leiningen.core.ssl/override-wagon-registry!) https-registry (resolve 'leiningen.core.ssl/https-registry) certs (mapcat read-certs (:certificates project)) context (make-context (into (default-certs) certs))] (override-wagon-registry! (https-registry context)) project))) (defn activate-middleware "A helper function to apply middleware and then load certificates and hooks, since we always do these three things together, at least so far." [project] (doto (apply-middleware project) (load-certificates) (load-hooks))) (defn project-with-profiles-meta [project profiles] ;;; should this dissoc :default? ;; (vary-meta project assoc :profiles (dissoc profiles :default)) (vary-meta project assoc :profiles profiles)) (defn- apply-profile-meta [default-meta profile] (if (map? profile) (let [profile (vary-meta profile (fn [m] (merge default-meta m)))] (if-let [scope (:pom-scope (meta profile))] (with-meta (update-in profile [:dependencies] (fn [deps] (map (fn [dep] (if (some #(= :scope %) dep) dep (-> dep (conj :scope) (conj (name scope))))) deps))) (meta profile)) profile)) profile)) (defn project-with-profiles [project] (let [profiles (merge (read-plugin-profiles project) (read-profiles project))] (project-with-profiles-meta project (->> (map (fn [[k p]] [k (apply-profile-meta (default-profile-metadata k) p)]) profiles) (into {}))))) (defn ^:internal init-profiles "Compute a fresh version of the project map, including and excluding the specified profiles." [project include-profiles & [exclude-profiles]] (let [project (with-meta (:without-profiles (meta project) project) (meta project)) include-profiles-meta (->> (expand-profiles-with-meta project include-profiles) (utils/last-distinct-by first)) include-profiles (map first include-profiles-meta) exclude-profiles (utils/last-distinct (expand-profiles project exclude-profiles)) normalize #(if (coll? %) (lookup-profile (:profiles project) %) [%]) exclude-profiles (mapcat normalize exclude-profiles) profile-map (apply dissoc (:profiles (meta project)) exclude-profiles) profiles (map (partial lookup-profile profile-map) include-profiles) normalized-profiles (map normalize-values profiles)] (-> project (apply-profiles normalized-profiles) (profile-scope-target-path include-profiles) (target-path-subdirs :compile-path) (target-path-subdirs :native-path) (absolutize-paths) (add-global-exclusions) (vary-meta merge {:without-profiles project :included-profiles include-profiles :excluded-profiles exclude-profiles :profile-inherited-meta include-profiles-meta})))) (def whitelist-keys "Project keys which don't affect the production of the jar (sans its name) should be propagated to the compilation phase and not stripped out." [:certificates :jar-name :local-repo :mirrors :offline? :repositories :uberjar-name :warn-on-reflection]) (defn retain-whitelisted-keys "Retains the whitelisted keys from the original map in the new one." [new original] (merge new (select-keys original whitelist-keys))) ;; # High-level profile operations (defn set-profiles "Compute a fresh version of the project map, with middleware applied, including and excluding the specified profiles." [project include-profiles & [exclude-profiles]] (-> project (init-profiles include-profiles exclude-profiles) (load-plugins) (activate-middleware))) (defn merge-profiles "Compute a fresh version of the project map with the given profiles merged into list of active profiles and the appropriate middleware applied." [project profiles] (let [{:keys [included-profiles excluded-profiles]} (meta project) profiles (expand-profiles project profiles)] (set-profiles project (concat included-profiles profiles) (remove (set profiles) excluded-profiles)))) (defn unmerge-profiles "Compute a fresh version of the project map with the given profiles unmerged from list of active profiles and the appropriate middleware applied." [project profiles] (let [{:keys [included-profiles excluded-profiles]} (meta project) profiles (expand-profiles project profiles)] (set-profiles project (remove (set profiles) included-profiles) (concat excluded-profiles profiles)))) (defn init-lein-classpath "Adds dependencies to Leiningen's classpath if required." [project] (when (= :leiningen (:eval-in project)) (doseq [path (classpath/get-classpath project)] (pomegranate/add-classpath path)))) (defn- load-repository-overrides "Loads any network-centric overrides specified in repository-overrides.clj. This feature allows certain features to be defined outside of the project file, but before the profiles are loaded. This is necessary because network operations are needed to complete the profile merging themselves and therefore they are not suited to defining network configuration items." [project] (let [overrides (-> (io/file (:root project) "repository-overrides.clj") (utils/read-file) (select-keys [:repositories :plugin-repositories :mirrors :certificates :local-repo]))] (merge project overrides))) (defn init-project "Initializes a project by loading certificates, plugins, middleware, etc. Also merges default profiles." ([project default-profiles] (-> (load-repository-overrides project) (doto (load-certificates) (init-lein-classpath) (load-plugins)) (project-with-profiles) (init-profiles default-profiles) (load-plugins) (activate-middleware))) ([project] (init-project project [:default]))) (defn add-profiles "Add the profiles in the given profiles map to the project map, taking care to preserve project map metadata. Note that these profiles are not merged, merely made available to merge by name." [project profiles-map] (-> (update-in project [:profiles] merge profiles-map) (vary-meta merge {:without-profiles (update-in (:without-profiles (meta project) project) [:profiles] merge profiles-map)}) (vary-meta update-in [:profiles] merge profiles-map))) (defn profile-annotations "Return a map of profile keyword to profile annotations for the profiles in :include-profiles." [project] (->> (map (juxt first (fn [[profile m]] (merge m (meta ((-> project meta :profiles) profile))))) (-> project meta :profile-inherited-meta)) (into {}))) (defn profiles-with-matching-meta "Return a sequence of profile keywords for the project profiles that have metadata that satisfies the predicate, pred." [project pred] (->> (-> project meta :profiles) (filter (comp pred meta val)) (map key))) (defn non-leaky-profiles "Return a sequence of profile keywords for the non-leaky profiles currently included in the project." [project] (->> (profile-annotations project) (remove (comp :leaky val)) (map key))) (defn pom-scope-profiles "Return a sequence of profile keywords for the currently active project profiles with :pom-scope equal to scope." [project scope] (->> (profile-annotations project) (filter (comp #(= scope (:pom-scope %)) val)) keys)) (defn read-raw "Read project file without loading certificates, plugins, middleware, etc." [source] (locking read-raw (binding [*ns* (find-ns 'leiningen.core.project)] (try (if (instance? Reader source) (load-reader source) (load-file source)) (catch Exception e (throw (Exception. (format "Error loading %s" source) e))))) (let [project (resolve 'leiningen.core.project/project)] (when-not project (throw (Exception. (format "%s must define project map" source)))) ;; return it to original state (ns-unmap 'leiningen.core.project 'project) @project))) (defn read "Read project map out of file, which defaults to project.clj. Also initializes the project; see read-raw for a version that skips init." ([file profiles] (init-project (read-raw file) profiles)) ([file] (read file [:default])) ([] (read "project.clj"))) ;; Basically just for re-throwing a more comprehensible error. (defn- read-dependency-project [project-file] (if (.exists project-file) (let [project (.getAbsolutePath project-file)] (try (read project) (catch Exception e (throw (Exception. (format "Problem loading %s" project) e))))) (warn "WARN ignoring checkouts directory" (.getParent project-file) "as it does not contain a project.clj file."))) (alter-var-root #'read-dependency-project memoize) (defn read-checkouts "Returns a list of project maps for this project's checkout dependencies." [project] (for [dep (.listFiles (io/file (:root project) "checkouts")) :let [project-file (.getCanonicalFile (io/file dep "project.clj")) checkout-project (read-dependency-project project-file)] :when checkout-project] checkout-project)) leiningen-2.9.1/leiningen-core/src/leiningen/core/ssl.clj000066400000000000000000000114121343535564500233670ustar00rootroot00000000000000(ns leiningen.core.ssl (:require [cemerick.pomegranate.aether :as aether] [clojure.java.io :as io] [leiningen.core.user :as user]) (:import java.security.KeyStore java.security.KeyStore$TrustedCertificateEntry java.security.Security java.security.cert.CertificateFactory javax.net.ssl.KeyManagerFactory javax.net.ssl.SSLContext javax.net.ssl.TrustManagerFactory javax.net.ssl.X509TrustManager java.io.FileInputStream org.apache.http.config.RegistryBuilder org.apache.http.conn.socket.PlainConnectionSocketFactory org.apache.http.conn.ssl.DefaultHostnameVerifier org.apache.http.conn.ssl.SSLConnectionSocketFactory org.apache.http.impl.conn.PoolingHttpClientConnectionManager org.apache.maven.wagon.providers.http.HttpWagon)) (defn ^TrustManagerFactory trust-manager-factory [^KeyStore keystore] (doto (TrustManagerFactory/getInstance "PKIX") (.init keystore))) (defn default-trust-managers [] (let [tmf (trust-manager-factory nil) tms (.getTrustManagers tmf)] (filter #(instance? X509TrustManager %) tms))) (defn key-manager-props [] (let [read #(java.lang.System/getProperty %)] (merge {:file (read "javax.net.ssl.keyStore") :type (read "javax.net.ssl.keyStoreType") :provider (read "javax.net.ssl.keyStoreProvider") :password (read "javax.net.ssl.keyStorePassword")} (-> (user/profiles) :user :key-manager-properties)))) (defn key-manager-factory [{:keys [file type provider password]}] (let [type (or type (KeyStore/getDefaultType)) fis (if-not (empty? file) (FileInputStream. file)) pwd (and password (.toCharArray password)) store (if provider (KeyStore/getInstance type provider) (KeyStore/getInstance type))] (.load store fis pwd) (when fis (.close fis)) (doto (KeyManagerFactory/getInstance (KeyManagerFactory/getDefaultAlgorithm)) (.init store pwd)))) (defn default-trusted-certs "Lists the CA certificates trusted by the JVM." [] (mapcat #(.getAcceptedIssuers %) (default-trust-managers))) (defn read-certs "Read one or more X.509 certificates in DER or PEM format." [f] (let [cf (CertificateFactory/getInstance "X.509") in (io/input-stream (or (io/resource f) (io/file f)))] (.generateCertificates cf in))) (defn make-keystore "Construct a KeyStore that trusts a collection of certificates." [certs] (let [ks (KeyStore/getInstance "jks")] (.load ks nil nil) (doseq [[i cert] (map vector (range) certs)] (.setEntry ks (str i) (KeyStore$TrustedCertificateEntry. cert) nil)) ks)) ;; TODO: honor settings from project.clj, not just user profile (defn make-sslcontext "Construct an SSLContext that trusts a collection of certificates." [trusted-certs] (let [ks (make-keystore trusted-certs) kmf (key-manager-factory (key-manager-props)) tmf (trust-manager-factory ks)] (doto (SSLContext/getInstance "TLS") (.init (.getKeyManagers kmf) (.getTrustManagers tmf) nil)))) (alter-var-root #'make-sslcontext memoize) (defn https-registry "Constructs a registry map that uses a given SSLContext for https." [context] (let [factory (SSLConnectionSocketFactory. context (DefaultHostnameVerifier.))] {"https" factory "http" PlainConnectionSocketFactory/INSTANCE})) (defn ^:deprecated https-scheme "Constructs a registry map that uses a given SSLContext for https. DEPRECATED: Use https-registry instead." ([context port] (if (not= port 443) ;; TODO: Should we support this? (throw (ex-info "Specifying port for https-scheme is not possible anymore." {:context context :port port})) (https-scheme context))) ([context] (binding [*out* *err*] (println "https-scheme is deprecated, use https-registry instead")) (https-registry context))) (defn- map->registry "Creates a Registry based of the given map." [m] (let [rb (RegistryBuilder/create)] (doseq [[scheme conn-sock-factory] m] (.register rb scheme conn-sock-factory)) (.build rb))) (defn override-wagon-registry! "Override the registry scheme used by the HTTP Wagon's Connection manager (used for Aether)." [registry] (let [cm (PoolingHttpClientConnectionManager. (map->registry registry))] (HttpWagon/setPoolingHttpClientConnectionManager cm))) (defn ^:deprecated register-scheme "Override the registry scheme used by the HTTP Wagon's Connection manager (used for Aether). DEPRECATED: Use override-wagon-registry! instead." [scheme] (binding [*out* *err*] (println "register-scheme is deprecated, use override-wagon-registry! instead")) (override-wagon-registry! scheme)) leiningen-2.9.1/leiningen-core/src/leiningen/core/user.clj000066400000000000000000000162721343535564500235550ustar00rootroot00000000000000(ns leiningen.core.user "Functions exposing user-level configuration." (:require [clojure.java.io :as io] [clojure.string :as str] [clojure.java.shell :as shell] [leiningen.core.utils :as utils]) (:import (com.hypirion.io Pipe) (org.apache.commons.io.output TeeOutputStream) (java.util.regex Pattern) (java.io ByteArrayOutputStream))) (defn getprop "Wrap System/getProperty for testing purposes." [prop-name] (System/getProperty prop-name)) (defn getenv "Wrap System/getenv for testing purposes." [name] (System/getenv name)) (defn leiningen-home "Return full path to the user's Leiningen home directory." [] (let [lein-home (getenv "LEIN_HOME") lein-home (or (and lein-home (io/file lein-home)) (io/file (System/getProperty "user.home") ".lein"))] (.getAbsolutePath (doto lein-home utils/mkdirs)))) ;; TODO: move all these memoized fns into delays (def init "Load the user's ~/.lein/init.clj file, if present." (memoize (fn [] (let [init-file (io/file (leiningen-home) "init.clj")] (when (.exists init-file) (try (load-file (.getAbsolutePath init-file)) (catch Exception e (.printStackTrace e)))))))) (defn- load-profiles-d-file "Returns a map entry containing the filename (without `.clj`) associated with its contents. The content will be tagged with its origin." [file] (try (let [kw (->> file .getName (re-find #".+(?=\.clj)") keyword) contents (vary-meta (utils/read-file file) ;; assumes the file exist merge {:origin (.getAbsolutePath file)})] [kw contents]) (catch Exception e (binding [*out* *err*] (println "Error reading" (.getName file) "from" (-> file .getParentFile .getAbsolutePath (str ":"))) (println (.getMessage e)))))) (def profiles-d-profiles "Load all Clojure files from the profiles.d folder in your Leiningen home if present. Returns a seq with map entries of the different profiles." (memoize (fn [] (let [profile-dir (io/file (leiningen-home) "profiles.d")] (if (.isDirectory profile-dir) (for [file (.listFiles profile-dir) :when (-> file .getName (.endsWith ".clj"))] (load-profiles-d-file file))))))) (def ^:internal load-profiles "Load profiles.clj from dir if present. Tags all profiles with its origin." (memoize (fn [dir] (if-let [contents (utils/read-file (io/file dir "profiles.clj"))] (utils/map-vals contents vary-meta merge {:origin (str (io/file dir "profiles.clj"))}))))) (def profiles "Load profiles.clj from your Leiningen home and profiles.d if present." (memoize (fn [] (let [error-fn (fn [a b] (binding [*out* *err*] (println "Error: A profile is defined in both" (-> a meta :origin) "and in" (-> b meta :origin))) (throw (ex-info "Multiple profiles defined in ~/.lein" {:exit-code 1})))] (if (not (System/getenv "LEIN_NO_USER_PROFILES")) (merge-with error-fn (load-profiles (leiningen-home)) (into {} (profiles-d-profiles)))))))) (defn gpg-program "Lookup the gpg program to use, defaulting to 'gpg'" [] (or (getenv "LEIN_GPG") "gpg")) (defn- get-english-env "Returns env vars as a map with clojure keywords and LANGUAGE set to 'en'" [] (let [env (System/getenv)] (assoc (zipmap (map keyword (keys env)) (vals env)) :LANGUAGE "en"))) (defn- as-env-strings [env] (into-array String (map (fn [[k v]] (str (name k) "=" v)) env))) (defn gpg "Shells out to (gpg-program) with the given arguments" [& args] (try (let [proc-env (as-env-strings (get-english-env)) proc-args (into-array String (concat [(gpg-program)] args)) proc (.exec (Runtime/getRuntime) proc-args proc-env)] (.addShutdownHook (Runtime/getRuntime) (Thread. (fn [] (.destroy proc)))) (with-open [out (.getInputStream proc) err-output (ByteArrayOutputStream.)] (let [pump-err (doto (Pipe. (.getErrorStream proc) (TeeOutputStream. System/err err-output)) .start)] (.join pump-err) (let [exit-code (.waitFor proc)] {:exit exit-code :out (slurp (io/reader out)) :err (slurp (io/reader (.toByteArray err-output)))})))) (catch java.io.IOException e {:exit 1 :out "" :err (.getMessage e)}))) (defn gpg-available? "Verifies (gpg-program) exists" [] (zero? (:exit (gpg "--version")))) (defn credentials-fn "Decrypt map from credentials.clj.gpg in Leiningen home if present." ([] (let [cred-file (io/file (leiningen-home) "credentials.clj.gpg")] (if (.exists cred-file) (credentials-fn cred-file)))) ([file] (let [{:keys [out err exit]} (gpg "--quiet" "--batch" "--decrypt" "--" (str file))] (if (pos? exit) (binding [*out* *err*] (println "Could not decrypt credentials from" (str file)) (println err) (println "See `lein help gpg` for how to install gpg.")) (binding [*read-eval* false] (read-string out)))))) (def credentials (memoize credentials-fn)) (defn- match-credentials [settings auth-map] (get auth-map (:url settings) (first (for [[re? cred] auth-map :when (and (instance? Pattern re?) (re-find re? (:url settings)))] cred)))) (defn- resolve-credential "Resolve key-value pair from result into a credential, updating result." [source-settings result [k v]] (letfn [(resolve [v] (cond (= :env v) (getenv (str "LEIN_" (str/upper-case (name k)))) (and (keyword? v) (= "env" (namespace v))) (getenv (str/upper-case (name v))) (= :gpg v) (get (match-credentials source-settings (credentials)) k) (coll? v) ;; collection of places to look (->> (map resolve v) (remove nil?) first) :else v))] (if (#{:username :password :passphrase :private-key-file} k) (assoc result k (resolve v)) (assoc result k v)))) (defn resolve-credentials "Applies credentials from the environment or ~/.lein/credentials.clj.gpg as they are specified and available." [settings] (let [gpg-creds (if (= :gpg (:creds settings)) (match-credentials settings (credentials))) resolved (reduce (partial resolve-credential settings) (empty settings) settings)] (if gpg-creds (dissoc (merge gpg-creds resolved) :creds) resolved))) (defn profile-auth "Look up credentials for a given repository in :auth profile." [settings] (if-let [repo-auth (-> (profiles) :auth :repository-auth)] (merge settings (match-credentials settings repo-auth)) settings)) leiningen-2.9.1/leiningen-core/src/leiningen/core/utils.clj000066400000000000000000000222071343535564500237320ustar00rootroot00000000000000(ns leiningen.core.utils (:require [clojure.java.io :as io] [clojure.java.shell :as sh]) (:import (com.hypirion.io RevivableInputStream) (clojure.lang LineNumberingPushbackReader) (java.io ByteArrayOutputStream PrintStream File FileDescriptor FileOutputStream FileInputStream InputStreamReader) (java.net URL))) (def rebound-io? (atom false)) (defn rebind-io! [] (when-not @rebound-io? (let [new-in (-> FileDescriptor/in FileInputStream. RevivableInputStream.)] (System/setIn new-in) (.bindRoot #'*in* (-> new-in InputStreamReader. LineNumberingPushbackReader.))) (reset! rebound-io? true))) (defn build-url "Creates java.net.URL from string" [url] (try (URL. url) (catch java.net.MalformedURLException _ (URL. (str "http://" url))))) (defmacro with-write-permissions "Runs body only if path is writeable, or - if it does not already exist - can be created." [path & body] `(let [p# ~path f# (new File p#)] (if (or (and (.exists f#) (.canWrite f#)) (and (not (.exists f#)) (some-> f# .getParentFile .canWrite))) (do ~@body) (throw (java.io.IOException. (str "Permission denied. Please check your access rights for " p#)))))) (defn read-file "Returns the first Clojure form in a file if it exists." [file] (if (.exists file) (try (read-string (slurp file)) (catch Exception e (binding [*out* *err*] ;; TODO: use main/warn for this in 3.0 (println "Error reading" (.getName file) "from" (.getParent file)) (if (zero? (.length file)) (println "File cannot be empty") (if (.contains (.getMessage e) "EOF while reading") (println "Invalid content was found") (println (.getMessage e))))))))) (defn symlink? "Checks if a File is a symbolic link or points to another file." [file] (let [canon (if-not (.getParent file) file (-> (.. file getParentFile getCanonicalFile) (File. (.getName file))))] (not= (.getCanonicalFile canon) (.getAbsoluteFile canon)))) (defn mkdirs "Make a given directory and its parents, but throw an Exception on failure." [f] ; whyyyyy does .mkdirs fail silently ugh (let [already-exists? (.exists (io/file f))] (when-not (or (.mkdirs (io/file f)) already-exists?) (throw (Exception. (str "Couldn't create directories: " (io/file f))))))) (defn relativize "Makes the filepath path relative to base. Assumes base is an ancestor to path, and that the path contains no '..'." [base path] ;; TODO: When moving to Java 1.7, use Path's relativize instead (let [base-uri (.toURI (io/file base)) path-uri (.toURI (io/file path))] (.. base-uri (relativize path-uri) (getPath)))) (defn ns-exists? [namespace] (or (find-ns (symbol namespace)) (some (fn [suffix] (-> (#'clojure.core/root-resource namespace) (subs 1) (str suffix) io/resource)) [".clj" ".cljc" (str clojure.lang.RT/LOADER_SUFFIX ".class")]))) (defn error [& args] (binding [*out* *err*] ;; TODO: use main/warn for this in 3.0 (apply println "Error:" args))) (defn require-resolve "Resolve a fully qualified symbol by first requiring its namespace." ([sym] (if-let [ns (namespace sym)] (when (ns-exists? ns) (let [ns (symbol ns)] (when-not (find-ns ns) (require ns))) (resolve sym)) (resolve sym))) ([ns sym] (require-resolve (symbol ns sym)))) ;; # OS detection (defn- get-by-pattern "Gets a value from map m, but uses the keys as regex patterns, trying to match against k instead of doing an exact match." [m k] (m (first (drop-while #(nil? (re-find (re-pattern %) k)) (keys m))))) (defn- get-with-pattern-fallback "Gets a value from map m, but if it doesn't exist, fallback to use get-by-pattern." [m k] (let [exact-match (m k)] (if (nil? exact-match) (get-by-pattern m k) exact-match))) (def ^:private native-names {"Mac OS X" :macosx "Windows" :windows "Linux" :linux "FreeBSD" :freebsd "OpenBSD" :openbsd "amd64" :x86_64 "x86_64" :x86_64 "x86" :x86 "i386" :x86 "arm" :arm "SunOS" :solaris "sparc" :sparc "Darwin" :macosx}) (defn get-os "Returns a keyword naming the host OS." [] (get-with-pattern-fallback native-names (System/getProperty "os.name"))) (defn get-arch "Returns a keyword naming the host architecture" [] (get-with-pattern-fallback native-names (System/getProperty "os.arch"))) (defn platform-nullsink "Returns a file destination that will discard output." [] (io/file (if (= :windows (get-os)) "NUL" "/dev/null"))) ;; The ordering on map-vals and filter-vals may seem strange, but it helps out ;; if you want to do stuff like (update m :foo map-vals f extra-args) (defn map-vals "Like 'update', but for all values in a map." [m f & args] (zipmap (keys m) (map #(apply f % args) (vals m)))) (defn filter-vals "Like filter, but for values over a map: If pred is satisfied on a value in m, then its entry is preserved, otherwise it is removed." [m pred] (->> (filter #(pred (val %)) m) (into {}))) ;; # Git ;; This is very similar to the read-file function above. The only differences ;; are the error messages and the transformations done on the content. (defn- git-file-contents "Returns the (trimmed) contents by the given git path, or nil if it is inacessible or nonexisting. If it exists and is not readable, a warning is printed." [git-dir ref-path] (let [ref (io/file git-dir ref-path)] (if (.canRead ref) (.trim (slurp ref)) (do (when (.exists ref) (binding [*out* *err*] ;; TODO: use main/warn for this in 3.0 (println "Warning: Contents of git file" (str ".git/" ref-path) "is not readable.") (println "(Check that you have the right permissions to read" "the .git repo)"))) nil)))) (defn ^:internal resolve-git-dir [project] (let [alternate-git-root (io/file (get-in project [:scm :dir])) git-dir-file (io/file (or alternate-git-root (:root project)) ".git")] (if (and (.isFile git-dir-file) (.canRead git-dir-file)) (io/file (second (re-find #"gitdir: (\S+)" (slurp (str git-dir-file))))) git-dir-file))) (defn- read-git-ref "Reads the commit SHA1 for a git ref path, or nil if no commit exist." [git-dir ref-path] (git-file-contents git-dir ref-path)) (defn- read-git-head-file "Reads the current value of HEAD by attempting to read .git/HEAD, returning the SHA1 or nil if none exists." [git-dir] (some->> (git-file-contents git-dir "HEAD") (re-find #"ref: (\S+)") (second) (read-git-ref git-dir))) ;; TODO: de-dupe with pom namespace (3.0?) (defn ^:internal read-git-head "Reads the value of HEAD and returns a commit SHA1, or nil if no commit exist." [git-dir] (try (let [git-ref (sh/sh "git" "rev-parse" "HEAD" :dir git-dir)] (if (= (:exit git-ref) 0) (.trim (:out git-ref)) (read-git-head-file git-dir))) (catch java.io.IOException e (read-git-head-file git-dir)))) (defn last-distinct "Like distinct, but retains the last version instead of the first version of a duplicate." [coll] (reverse (distinct (reverse coll)))) ;; Inspired by distinct-by from medley (https://github.com/weavejester/medley), ;; also under the EPL 1.0. (defn last-distinct-by "Returns a lazy sequence of the elements of coll, removing any elements that return duplicate values when passed to a function f. Only the last element that is a duplicate is preserved." [f coll] (let [step (fn step [xs seen] (lazy-seq ((fn [[x :as xs] seen] (when-let [s (seq xs)] (let [fx (f x)] (if (contains? seen fx) (recur (rest s) seen) (cons x (step (rest s) (conj seen fx))))))) xs seen)))] (reverse (step (reverse coll) #{})))) (defn ancestor? "Is a an ancestor of b?" [a b] (let [hypothetical-ancestor (.getCanonicalPath (io/file a)) hypothetical-descendant (.getCanonicalPath (io/file b))] (and (.startsWith hypothetical-descendant hypothetical-ancestor) (not (= hypothetical-descendant hypothetical-ancestor))))) (defmacro with-system-out-str "Like with-out-str, but for System/out." [& body] `(try (let [o# (ByteArrayOutputStream.)] (System/setOut (PrintStream. o#)) ~@body (.toString o#)) (finally (System/setOut (-> FileDescriptor/out FileOutputStream. PrintStream.))))) (defmacro with-system-err-str "Like with-out-str, but for System/err." [& body] `(try (let [o# (ByteArrayOutputStream.)] (System/setErr (PrintStream. o#)) ~@body (.toString o#)) (finally (System/setErr (-> FileDescriptor/err FileOutputStream. PrintStream.))))) leiningen-2.9.1/leiningen-core/test/000077500000000000000000000000001343535564500173655ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/test/leiningen/000077500000000000000000000000001343535564500213355ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/test/leiningen/bluuugh.clj000066400000000000000000000002161343535564500235010ustar00rootroot00000000000000(ns leiningen.bluuugh "Dummy task for tests.") (defn ^:no-project-needed bluuugh [project] (println "This is a dummy task for tests."))leiningen-2.9.1/leiningen-core/test/leiningen/core/000077500000000000000000000000001343535564500222655ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/test/leiningen/core/test/000077500000000000000000000000001343535564500232445ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/test/leiningen/core/test/classpath.clj000066400000000000000000000212001343535564500257130ustar00rootroot00000000000000(ns leiningen.core.test.classpath (:use [clojure.test] [leiningen.core.classpath]) (:require [clojure.java.io :as io] [leiningen.core.user :as user] [leiningen.test.helper :as lthelper] [leiningen.core.project :as project]) (:import (java.io File))) (use-fixtures :once (fn [f] ;; Can't have user-level profiles interfering! (with-redefs [user/profiles (constantly {}) user/credentials (constantly nil)] (f)))) (defn m2-file [f] (io/file (System/getProperty "user.home") ".m2" "repository" f)) (def project {:managed-dependencies '[[org.clojure/clojure "1.3.0"]] :dependencies '[[org.clojure/clojure] [ring/ring-core "1.0.0" :exclusions [commons-codec]]] :checkout-deps-shares [:source-paths :resource-paths :compile-path #(lthelper/pathify (str (:root %) "/foo"))] :repositories project/default-repositories :root "/tmp/lein-sample-project" :target-path "/tmp/lein-sample-project/target" :source-paths ["/tmp/lein-sample-project/src"] :resource-paths ["/tmp/lein-sample-project/resources"] :test-paths ["/tmp/lein-sample-project/test"]}) (deftest test-resolve-deps (doseq [f (reverse (file-seq (io/file (:root project))))] (when (.exists f) (io/delete-file f))) (is (= #{(m2-file "org/clojure/clojure/1.3.0/clojure-1.3.0.jar") (m2-file "commons-io/commons-io/1.4/commons-io-1.4.jar") (m2-file "javax/servlet/servlet-api/2.5/servlet-api-2.5.jar") (m2-file "ring/ring-core/1.0.0/ring-core-1.0.0.jar") (m2-file (str "commons-fileupload/commons-fileupload/1.2.1/" "commons-fileupload-1.2.1.jar"))} (set (resolve-managed-dependencies :dependencies :managed-dependencies project))))) (deftest test-dependency-hierarchy (doseq [f (reverse (file-seq (io/file (:root project))))] (when (.exists f) (io/delete-file f))) (is (= '{[org.clojure/clojure "1.3.0"] nil [ring/ring-core "1.0.0" :exclusions [[commons-codec]]] {[commons-fileupload "1.2.1"] nil [commons-io "1.4"] nil [javax.servlet/servlet-api "2.5"] nil}} (managed-dependency-hierarchy :dependencies :managed-dependencies project)))) (def directories (vec (map lthelper/pathify ["/tmp/lein-sample-project/test" "/tmp/lein-sample-project/src" "/tmp/lein-sample-project/resources"]))) (def libs #{(str (m2-file "commons-io/commons-io/1.4/commons-io-1.4.jar")) (str (m2-file "javax/servlet/servlet-api/2.5/servlet-api-2.5.jar")) (str (m2-file "ring/ring-core/1.0.0/ring-core-1.0.0.jar")) (str (m2-file "commons-fileupload/commons-fileupload/1.2.1/commons-fileupload-1.2.1.jar")) (str (m2-file "org/clojure/clojure/1.3.0/clojure-1.3.0.jar"))}) (deftest test-classpath (let [classpath (get-classpath project)] (is (= (set classpath) (into libs directories))) (is (= directories (take 3 classpath))) (is (= libs (set (drop 3 classpath)))))) (defn canonical [& args] (.getCanonicalPath ^File (apply io/file args))) (deftest test-checkout-deps (let [d1 (io/file (:root project) "checkouts" "d1")] (try (.mkdirs d1) (spit (io/file d1 "project.clj") (pr-str '(defproject hello "1.0"))) (is (= (for [path ["src" "dev-resources" "resources" "target/classes" "foo"]] (lthelper/pathify (canonical "/tmp/lein-sample-project/checkouts/d1" path))) (#'leiningen.core.classpath/checkout-deps-paths project))) (finally ;; can't recur from finally (dorun (map #(.delete ^File %) (reverse (file-seq d1)))))))) (try ;; nio is required for symlinks but requires Java 7 (import (java.nio.file Files Paths) (java.nio.file.attribute FileAttribute)) (deftest test-checkout-symlink-unification (let [link! (fn link! [from to] (java.nio.file.Files/createSymbolicLink (.toPath (io/file from)) (.toPath (io/file to)) (into-array java.nio.file.attribute.FileAttribute nil))) d1 (io/file (:root project) "deps" "d1") d2 (io/file (:root project) "deps" "d2") l1 (io/file (:root project) "checkouts" "d1") l2a (io/file (:root project) "checkouts" "d2") l2b (io/file d1 "checkouts" "d2")] (try (.mkdirs d1) (.mkdirs d2) (.mkdirs (io/file (:root project) "checkouts")) (.mkdirs (io/file d1 "checkouts")) (link! l1 d1) (link! l2a d1) (link! l2b (io/file "../../d2")) (spit (io/file d1 "project.clj") (str "(defproject p1 \"1.0\" :dependencies [[p2 \"1.0\"]] " ":checkout-deps-shares ^:replace " "[:source-paths #=(eval leiningen.core.classpath/checkout-deps-paths)])")) (spit (io/file d2 "project.clj") "(defproject p2 \"1.0\")") (is (= (for [dep ["d1" "d2"] path ["src"]] (canonical (:root project) "deps" dep path)) (#'leiningen.core.classpath/checkout-deps-paths (assoc project :checkout-deps-shares [:source-paths #'leiningen.core.classpath/checkout-deps-paths])))) (finally ;; can't recur from finally (doseq [d [d1 d2 l1 l2a l2b] f (reverse (file-seq d))] (.delete ^File f))) ))) (catch ClassNotFoundException ex nil)) (deftest test-add-auth (with-redefs [user/credentials (constantly {"https://sekrit.info/repo" {:username "milgrim" :password "reindur"}}) user/profiles (constantly {:auth {:repository-auth {#"clojars" {:username "flynn" :password "flotilla"}}}})] (is (= [["clojars" {:url "http://clojars.org/repo" :username "flynn" :password "flotilla"}] ["sonatype" {:url "https://oss.sonatype.org/"}] ["internal" {:password "reindur" :username "milgrim" :url "https://sekrit.info/repo"}]] (map add-repo-auth [["clojars" {:url "http://clojars.org/repo"}] ["sonatype" {:url "https://oss.sonatype.org/"}] ["internal" {:url "https://sekrit.info/repo" :username :gpg :password :gpg}]]))))) (deftest test-normalize-dep-vectors (testing "dep vectors with string version" (is (= ['foo/bar "1.0.0"] (normalize-dep-vector ['foo/bar "1.0.0"]))) (is (= ['foo/bar "1.0.0" :classifier "test"] (normalize-dep-vector ['foo/bar "1.0.0" :classifier "test"]))) (is (= ['foo/bar "1.0.0" :classifier "test" :exclusions ['foo/baz]] (normalize-dep-vector ['foo/bar "1.0.0" :classifier "test" :exclusions ['foo/baz]])))) (testing "dep vectors with keyword version (e.g., for use with lein-modules)" (is (= ['foo/bar :version] (normalize-dep-vector ['foo/bar :version]))) (is (= ['foo/bar :version :classifier "test"] (normalize-dep-vector ['foo/bar :version :classifier "test"]))) (is (= ['foo/bar :version :classifier "test" :exclusions ['foo/baz]] (normalize-dep-vector ['foo/bar :version :classifier "test" :exclusions ['foo/baz]])))) (testing "dep vectors with explicit nils for versions (managed dependencies)" (is (= ['foo/bar nil] (normalize-dep-vector ['foo/bar nil]))) (is (= ['foo/bar nil :classifier "test"] (normalize-dep-vector ['foo/bar nil :classifier "test"]))) (is (= ['foo/bar nil :classifier "test" :exclusions ['foo/baz]] (normalize-dep-vector ['foo/bar nil :classifier "test" :exclusions ['foo/baz]])))) (testing "dep vectors with implicit nils for versions (managed dependencies)" (is (= ['foo/bar nil] (normalize-dep-vector ['foo/bar]))) (is (= ['foo/bar nil :classifier "test"] (normalize-dep-vector ['foo/bar :classifier "test"]))) (is (= ['foo/bar nil :classifier "test" :exclusions ['foo/baz]] (normalize-dep-vector ['foo/bar :classifier "test" :exclusions ['foo/baz]]))))) leiningen-2.9.1/leiningen-core/test/leiningen/core/test/eval.clj000066400000000000000000000107111343535564500246650ustar00rootroot00000000000000(ns leiningen.core.test.eval (:require [clojure.test :refer :all] [leiningen.core.eval :refer :all] [clojure.java.io :as io] [clojure.set :as set] [leiningen.core.classpath :as classpath] [leiningen.test.helper :as lthelper] [leiningen.core.project :as project]) (:import (java.io File))) (def project {:managed-dependencies '[[org.clojure/clojure "1.3.0"]] :dependencies '[[org.clojure/clojure]] :root "/tmp/lein-sample-project" :repositories project/default-repositories :target-path "/tmp/lein-sample-project/target" :source-paths ["/tmp/lein-sample-project/src"] :resource-paths ["/tmp/lein-sample-project/resources"] :test-paths ["/tmp/lein-sample-project/test"] :compile-path "/tmp/lein-sample-project/classes" :name "test" :group "test" :version "1.0.0"}) (deftest test-eval-in-project (doseq [where [:subprocess :leiningen :classloader]] (let [file (File/createTempFile "lein-eval-test" "")] (eval-in-project (assoc project :eval-in where :prep-tasks []) `(spit ~(.getPath file) (eval "{:foo \"bar\"}"))) (is (= "{:foo \"bar\"}" (slurp file))) (.delete file)))) (deftest test-classpath-directories-created (doseq [path (concat (:source-paths project) (:test-paths project) (:resource-paths project))] (let [file (File/createTempFile "lein-eval-test" "")] (eval-in-project project `(do (.mkdirs (clojure.java.io/file ~path)) (spit ~(str path "/foo.txt") "Hello World") (when-let [f# (clojure.java.io/resource "foo.txt")] (spit ~(.getPath file) (slurp f#)))) `(require 'clojure.java.io)) (is (= "Hello World" (slurp file))) (.delete (io/file (str path "/foo.txt"))) (.delete (io/file path)) (.delete file)))) (deftest test-jvm-opts (is (= ["-Dhello=\"guten tag\"" "-XX:+HeapDumpOnOutOfMemoryError"] (get-jvm-opts-from-env (str "-Dhello=\"guten tag\" " "-XX:+HeapDumpOnOutOfMemoryError")))) (is (= ["-Dfoo=bar" "-Dbar=baz"] (get-jvm-opts-from-env (str " -Dfoo=bar" " -Dbar=baz")))) (is (= ["-Dfoo='ba\"r'" "-Dbar=\"ba\"'z'" "arg"] (get-jvm-opts-from-env (str " -Dfoo='ba\"r'" " -Dbar=\"ba\"'z'" " arg"))))) (deftest test-file-encoding-in-jvm-args (is (contains? (set (#'leiningen.core.eval/get-jvm-args project)) (str "-Dfile.encoding=" (System/getProperty "file.encoding"))))) (deftest test-get-jvm-args-with-proxy-settings ;; Mock get-proxy-settings to return test values (with-redefs [classpath/get-proxy-settings (fn ([] {:host "foo.com" :port 8080}) ([https] {:host "secure-foo.com", :port 443}))] (let [args (set (shell-command project 'repl))] (is (and (contains? args "-Dhttp.proxyHost=foo.com") (contains? args "-Dhttp.proxyPort=8080") (contains? args "-Dhttps.proxyHost=secure-foo.com") (contains? args "-Dhttps.proxyPort=443")))))) (deftest test-java-agent (let [p {:java-agents '[[com.newrelic.agent.java/newrelic-agent "2.18.0" :bootclasspath true] [nodisassemble "0.1.2" :options "hello"]] :dependencies '[[slamhound "1.3.0"]] :repositories project/default-repositories} [newrelic newrelic-bootcp nodisassemble] (classpath-arg p)] (is (.endsWith newrelic (lthelper/fix-path-delimiters (str "/com/newrelic/agent/java/newrelic-agent" "/2.18.0/newrelic-agent-2.18.0.jar")))) (is (re-find #"bootclasspath.*newrelic.*jar" newrelic-bootcp)) (is (re-find #"-javaagent:.*nodisassemble-0.1.2.jar=hello" nodisassemble)))) (deftest test-sh-with-exit-code-successful-command (with-redefs [sh (constantly 0)] (is (= 0 (sh-with-exit-code "Shouldn't see me." "ls"))))) (deftest test-sh-with-exit-code-failed-command (with-redefs [sh (constantly 1)] (is (thrown-with-msg? Exception #"Should see me. ls exit code: 1" (sh-with-exit-code "Should see me" "ls"))))) leiningen-2.9.1/leiningen-core/test/leiningen/core/test/helper.clj000066400000000000000000000005271343535564500252210ustar00rootroot00000000000000(ns leiningen.core.test.helper) (defn abort-msg "Catches main/abort thrown by calling f on its args and returns its error message." [f & args] (with-out-str (binding [*err* *out*] (try (apply f args) (catch clojure.lang.ExceptionInfo e (when-not (:exit-code (ex-data e)) (throw e))))))) leiningen-2.9.1/leiningen-core/test/leiningen/core/test/main.clj000066400000000000000000000157771343535564500247030ustar00rootroot00000000000000(ns leiningen.core.test.main (:use [clojure.test] [leiningen.core.main])) ;; Shamelessly stolen from ;; https://github.com/clojure/clojure/blob/master/test/clojure/test_clojure/main.clj#L28 (defmacro with-err-str "Evaluates exprs in a context in which *err* is bound to a fresh StringWriter. Returns the string created by any nested printing calls." [& body] `(let [s# (new java.io.StringWriter) p# (new java.io.PrintWriter s#)] (binding [*err* p#] ~@body (str s#)))) (deftest test-logs-sent-to-*err* (testing "main/warn sent to *err*" (is (= "Warning message\n" (with-err-str (warn "Warning message")))))) (deftest test-lookup-alias (testing "meta merging" (let [project {:aliases {"a" ^:foo ["root"] "b" ^:bar ["a"] "c" ^{:pass-through-help false :doc "Yo"} ["b"] "d" ^:pass-through-help ["c"]}}] (are [task m] (= (meta (lookup-alias task project)) m) "a" {:foo true} "b" {:bar true} "c" {:doc "Yo" :pass-through-help false} "d" {:pass-through-help true})))) (deftest test-task-args-help-pass-through (let [project {:aliases {"sirius-p" ["sirius" "partial"] "s" "sirius" "s-p" ["s" "partial"] "sirius-pp" ["sirius-p" "foo"] "sp" "s-p" "test" "test" "ohai" ^:pass-through-help ["run" "-m" "o.hai"] "aliaso" ["ohai"] "aliaso2" ["ohai"]}}] (testing "with :pass-through-help meta" (testing "on a var" (are [res arg] (= res (task-args arg project)) ["help" ["sirius"]] ["help" "sirius"] ["sirius" ["-h"]] ["sirius" "-h"] ["sirius" ["-?"]] ["sirius" "-?"] ["sirius" ["--help"]] ["sirius" "--help"] ["sirius" []] ["sirius"])) (testing "on an alias" (are [res arg] (= res (task-args arg project)) ["help" ["sirius-p"]] ["help" "sirius-p"] ["help" ["s"]] ["help" "s"] ["sirius" ["-h"]] ["s" "-h"] [["sirius" "partial"] ["-?"]] ["sirius-p" "-?"] ["sirius" ["--help"]] ["s" "--help"] [["sirius" "partial"] []] ["sirius-p"] [["sirius" "partial"] []] ["s-p"] [["sirius" "partial"] []] ["sp"] [["sirius" "partial" "foo"] ["bar"]] ["sirius-pp" "bar"] ["test" []] ["test"] ["sirius" []] ["s"] [["run" "-m" "o.hai"] ["-h"]] ["ohai" "-h"] [["run" "-m" "o.hai"] ["-h"]] ["aliaso" "-h"] [["run" "-m" "o.hai"] ["-h"]] ["aliaso2" "-h"] [["run" "-m" "o.hai"] ["--help"]] ["ohai" "--help"] [["run" "-m" "o.hai"] ["help"]] ["ohai" "help"]))))) (deftest test-matching-arity (is (not (matching-arity? (resolve-task "bluuugh") ["bogus" "arg" "s"]))) (is (matching-arity? (resolve-task "bluuugh") [])) (is (matching-arity? (resolve-task "var-args") [])) (is (matching-arity? (resolve-task "var-args") ["test-core" "hey"])) (is (not (matching-arity? (resolve-task "one-or-two") []))) (is (matching-arity? (resolve-task "one-or-two") ["clojure"])) (is (matching-arity? (resolve-task "one-or-two") ["clojure" "2"])) (is (not (matching-arity? (resolve-task "one-or-two") ["clojure" "2" "3"])))) (deftest partial-tasks (are [task args] (matching-arity? (resolve-task task) args) ["one-or-two" "clojure"] ["2"] ["one-or-two" "clojure" "2"] [] ["fixed-and-var-args" "one"] ["two"] ["fixed-and-var-args" "one" "two"] [] ["fixed-and-var-args" "one" "two"] ["more"]) (are [task args] (not (matching-arity? (resolve-task task) args)) ["one-or-two" "clojure"] ["2" "3"] ["one-or-two" "clojure" "2"] ["3"] ["fixed-and-var-args" "one"] [])) (deftest test-versions-match (is (versions-match? "1.2.12" "1.2.12")) (is (versions-match? "3.0" "3.0")) (is (versions-match? " 12.1.2" "12.1.2 ")) (is (not (versions-match? "1.2" "1.3"))) (is (not (versions-match? "1.2.0" "1.2"))) (is (not (versions-match? "1.2" "1.2.0"))) (is (versions-match? "2.1.3-SNAPSHOT" "2.1.3")) (is (versions-match? " 2.1.3-SNAPSHOT" "2.1.3")) (is (versions-match? "2.1.3" "2.1.3-FOO")) (is (not (versions-match? "3.0.0" "3.0.1-BAR")))) (deftest test-version-satisfies (is (version-satisfies? "1.5.0" "1.4.2")) (is (not (version-satisfies? "1.4.2" "1.5.0"))) (is (version-satisfies? "1.2.3" "1.1.1")) (is (version-satisfies? "1.2.0" "1.2")) (is (version-satisfies? "1.2" "1")) (is (not (version-satisfies? "1.67" "16.7")))) (deftest one-or-two-args (try (binding [*err* (java.io.StringWriter.)] (resolve-and-apply {:root true} ["one-or-two"])) (catch clojure.lang.ExceptionInfo e (re-find #"(?s)Wrong number of arguments to one-or-two task.*Expected \[one\] or \[one two\]" (.getMessage e))))) (deftest zero-args-msg (try (binding [*err* (java.io.StringWriter.)] (resolve-and-apply {:root true} ["zero" "too" "many" "args"])) (catch clojure.lang.ExceptionInfo e (re-find #"(?s)Wrong number of arguments to zero task.*Expected \[\]" (.getMessage e))))) (def ^:private distance @#'leiningen.core.main/distance) (deftest test-damerau-levensthein (is (zero? (distance "run" "run"))) (is (zero? (distance "uberjar" "uberjar"))) (is (zero? (distance "classpath" "classpath"))) (is (zero? (distance "with-profile" "with-profile"))) (is (= 1 (distance "rep" "repl"))) (is (= 1 (distance "est" "test"))) (is (= 1 (distance "java" "javac"))) (is (= 1 (distance "halp" "help"))) (is (= 1 (distance "lien" "lein"))) (is (= 4 (distance "" "repl"))) (is (= 6 (distance "foobar" ""))) (is (= 2 (distance "erlp" "repl"))) (is (= 2 (distance "deploy" "epdloy"))) (is (= 3 (distance "pugared" "upgrade")))) (deftest test-parse-options (is (= (parse-options ["--chicken"]) [{:--chicken true} '()])) (is (= (parse-options ["--beef" "rare"]) [{:--beef "rare"} []])) (is (= (parse-options [":fish" "salmon"]) [{:fish "salmon"} []])) (is (= (parse-options ["salmon" "trout"]) [{} ["salmon" "trout"]])) (is (= (parse-options ["--to-dir" "test2" "--ham"]) [{:--ham true, :--to-dir "test2"} []])) (is (= (parse-options ["--to-dir" "test2" "--ham" "--" "pate"]) [{:--ham true, :--to-dir "test2"} ["pate"]])) (is (= (parse-options ["--ham" "--to-dir" "test2" "pate"]) [{:--ham true, :--to-dir "test2"} ["pate"]])) (is (= (parse-options ["--to-dir" "test2" "--ham" "--"]) [{:--ham true, :--to-dir "test2"} []]))) (deftest test-spliced-project-values (let [p {:aliases {"go" ["echo" "write" :project/version]} :version "seventeen" :eval-in :leiningen} out (with-out-str (resolve-and-apply p ["go"]))] (is (= "write seventeen\n" out)))) leiningen-2.9.1/leiningen-core/test/leiningen/core/test/mirrors.clj000066400000000000000000000017741343535564500254440ustar00rootroot00000000000000(ns leiningen.core.test.mirrors (:require [clojure.test :refer :all] [cemerick.pomegranate :as pom] [leiningen.core.project :refer [defproject init-project]])) ;; Regression test for Issue #1555 (defproject mirrors-work-ok-with-plugins-project "0.0.0" ;; we need to use a sequence of pairs rather than a map to ;; reproduce the bug; IRL maps got converted to seqs somehow or ;; another anyhow, but apparently not by init-project. :mirrors [["central" {:name "foo" :url "https://repo1.maven.org/maven2/"}]] ;; Have to have a plugin to reproduce :plugins [[lein-pprint "1.1.1"]]) (deftest ^:online mirrors-work-ok-with-plugins ;; turn off add-classpath so we don't actually mutate the classpath; ;; we're still hitting the internet, and there's probably something ;; in pomegranate we could redef to prevent that, but I haven't ;; figured out what it is exactly. (with-redefs [pom/add-classpath (constantly nil)] (is (init-project project)))) leiningen-2.9.1/leiningen-core/test/leiningen/core/test/pedantic.clj000066400000000000000000000125411343535564500255300ustar00rootroot00000000000000(ns leiningen.core.test.pedantic (:require [clojure.test :refer :all] [clojure.java.io :as io] [leiningen.core.pedantic :as pedantic] [cemerick.pomegranate.aether :as aether])) (def tmp-dir (io/file (System/getProperty "java.io.tmpdir") "pedantic")) (def tmp-local-repo-dir (io/file tmp-dir "local-repo")) (defn delete-recursive [dir] (when (.isDirectory dir) (doseq [file (.listFiles dir)] (delete-recursive file))) (.delete dir)) (defn clear-tmp [f] (delete-recursive (io/file tmp-dir)) (f)) (defn get-versions [name repo] (let [name (symbol name)] (map second (filter #(= name (first %)) (keys repo))))) (defn make-pom-string [name version deps] (str " 4.0.0 " name " " name " jar " version " " name "" (if-not (empty? deps) (apply str "" (clojure.string/join "\n" (for [[n v] deps] (str " " n " "n" "v" "))) "")) " ")) (defn make-metadata [name versions] (str " " name " " name " " (clojure.string/join "\n" (for [v versions] (str ""v""))) " 20120810193549 ")) (defn add-repo [repo] (fn [f] (aether/register-wagon-factory! "fake" #(reify org.apache.maven.wagon.Wagon (getRepository [_] (proxy [org.apache.maven.wagon.repository.Repository] [])) (^void connect [_ ^org.apache.maven.wagon.repository.Repository _ ^org.apache.maven.wagon.authentication.AuthenticationInfo _ ^org.apache.maven.wagon.proxy.ProxyInfoProvider _]) (disconnect [_]) (removeTransferListener [_ _]) (addTransferListener [_ _]) (setTimeout [_ _]) (setInteractive [_ _]) (get [_ name file] (let [[n _ version] (clojure.string/split name #"/")] (if (= name (str n "/" n "/maven-metadata.xml")) (if-let [versions (get-versions n repo)] (spit file (make-metadata n versions)) (spit file "")) (if-let [deps (repo [(symbol n) version])] (if (re-find #".pom$" name) (spit file (make-pom-string n version deps)) (spit file "")) (throw (org.apache.maven.wagon.ResourceDoesNotExistException. "")))))))) (f))) (def ranges (atom [])) (def overrides (atom [])) (defn reset-state [f] (reset! ranges []) (reset! overrides []) (f)) (defn resolve-deps [coords] (aether/resolve-dependencies :coordinates coords :repositories {"test-repo" {:url "fake://ss" :checksum false}} :local-repo tmp-local-repo-dir :repository-session-fn #(-> % aether/repository-session (#'pedantic/use-transformer ranges overrides)))) (defmulti translate type) (defmethod translate :default [x] x) (defmethod translate java.util.List [l] (remove nil? (map translate l))) (defmethod translate java.util.Map [m] (into {} (map (fn [[k v]] [k (translate v)]) m))) (defmethod translate org.eclipse.aether.graph.DependencyNode [n] (if-let [a (#'pedantic/node->artifact-map n)] [(symbol (:artifactId a)) (:version a)])) (def repo '{[a "1"] [] [a "2"] [] [aa "2"] [[a "2"]] [range "1"] [[a "[1,)"]] [range "2"] [[a "[2,)"]]}) (use-fixtures :once (add-repo repo)) (use-fixtures :each clear-tmp) (use-fixtures :each reset-state) (deftest top-level-overrides-transative-later (resolve-deps '[[a "1"] [aa "2"]]) (is (= @ranges [])) (is (= (translate @overrides) '[{:accepted {:node [a "1"] :parents []} :ignoreds [{:node [a "2"] :parents [[aa "2"]]}] :ranges []}]))) (deftest ranges-are-found (resolve-deps '[[range "1"]]) (is (= (translate @ranges) '[{:node [a "1"] :parents [[range "1"]]} {:node [a "2"] :parents [[range "1"]]}])) (is (= @overrides []))) (deftest range-causes-other-transative-to-ignore-top-level (resolve-deps '[[a "1"] [aa "2"] [range "2"]]) (is (= (translate @ranges) '[{:node [a "2"] :parents [[range "2"]]}])) (is (= (translate @overrides) '[{:accepted {:node [a "2"] :parents [[aa "2"]]} :ignoreds [{:node [a "1"] :parents []}] :ranges [{:node [a "2"] :parents [[range "2"]]}]}]))) leiningen-2.9.1/leiningen-core/test/leiningen/core/test/project.clj000077500000000000000000000626501343535564500254200ustar00rootroot00000000000000(ns leiningen.core.test.project (:refer-clojure :exclude [read]) (:use [clojure.test] [leiningen.core.project :as project]) (:require [leiningen.core.user :as user] [leiningen.core.test.helper :refer [abort-msg]] [leiningen.test.helper :as lthelper] [leiningen.core.utils :as utils] [clojure.java.io :as io]) (:import (java.io StringReader))) (use-fixtures :once (fn [f] ;; Can't have user-level profiles interfering! (with-redefs [user/profiles (constantly {}) user/credentials (constantly nil) project/warn-once #'project/warn] (f)))) (defn make-project "Make put a project map's :profiles on it's metadata" [m] (project-with-profiles-meta m (:profiles m))) (def paths {:source-paths ["src"], :test-paths ["test"], :resource-paths ["dev-resources" "resources"], :compile-path "target/classes", :native-path "target/native", :target-path "target"}) (def expected {:name "leiningen", :group "leiningen", :version "2.0.0-SNAPSHOT", :url "https://github.com/technomancy/leiningen" :disable-implicit-clean true, :eval-in :leiningen, :license {:name "Eclipse Public License"} :dependencies `[[leiningen-core/leiningen-core "2.0.0-SNAPSHOT"] [clucy/clucy "0.2.2" :exclusions [[org.clojure/clojure]]] [lancet/lancet "1.0.1"] [robert/hooke "1.1.2"] [stencil/stencil "0.2.0"] [~(symbol "net.3scale" "3scale-api") "3.0.2"] [clj-http/clj-http "3.4.1"] [nrepl/nrepl "0.6.0" :exclusions [[org.clojure/clojure]]] [clojure-complete/clojure-complete "0.2.5" :exclusions [[org.clojure/clojure]]]], :twelve 12 ; testing unquote :repositories [["central" {:url "https://repo1.maven.org/maven2/" :snapshots false}] ["clojars" {:url "https://repo.clojars.org/"}]]}) (deftest test-read-project (let [actual (read (.getFile (io/resource "p1.clj")))] (doseq [[k v] expected] (is (= v (k actual)))) (doseq [[k path] paths :when (string? path)] (is (= (lthelper/pathify (str (:root actual) "/" path)) (k actual)))) (doseq [[k path] paths :when (coll? path)] (is (= (for [p path] (lthelper/pathify (str (:root actual) "/" p))) (k actual)))))) (deftest test-read-project-from-reader (let [project-string "(defproject foo \"0.0.1-SNAPSHOT\" :description \"foo\")" project-reader (StringReader. project-string) project (read project-reader)] (is (= "foo" (:group project))) (is (= "foo" (:name project))) (is (= "foo" (:description project))))) ;; TODO: test omit-default ;; TODO: test reading project that doesn't def project (deftest test-replace-repositories (let [actual (read (.getFile (io/resource "replace-repositories.clj")))] (is (= 1 (-> actual :repositories count))))) (deftest test-retain-profile-metadata (let [actual (read (.getFile (io/resource "profile-metadata.clj"))) profiles (:profiles actual)] (is (true? (-> profiles :bar :dependencies meta :please-keep-me))) (is (true? (-> profiles :bar :repositories meta :replace))) (is (true? (-> profiles :baz :dependencies meta :hello))) (is (true? (-> profiles :baz :repositories meta :displace))))) (deftest test-alias-in-profiles (let [actual (read (.getFile (io/resource "profile-metadata.clj")))] (is (= ["my" "java" "opts"] (-> actual :profiles :baz :jvm-opts))))) (deftest test-merge-profile-displace-replace (let [test-profiles {:carmine {:foo [3 4]} :carmined {:foo ^:displace [3 4]} :carminer {:foo ^:replace [3 4]} :blue {:foo [5 6]} :blued {:foo ^:displace [5 6]} :bluer {:foo ^:replace [5 6]} :jade {:foo [7 8]} :jaded {:foo ^:displace [7 8]} :jader {:foo ^:replace [7 8]}} test-project (fn [p] (project-with-profiles-meta p (merge test-profiles (:profiles p))))] (testing "that :^displace throws away the value if another exist" (is (= [1 2] (-> (make (test-project {:foo [1 2]})) (merge-profiles [:carmined]) :foo))) (is (= [1 2 5 6] (-> (make (test-project {:foo [1 2]})) (merge-profiles [:carmined :blue :jaded]) :foo))) (is (= [5 6] (-> (make (test-project {:foo ^:displace [1 2]})) (merge-profiles [:carmined :blued]) :foo))) (is (= [7 8 5 6] (-> (make (test-project {:foo ^:displace [1 2]})) (merge-profiles [:carmined :jade :blued :blue]) :foo)))) (testing "that :^displace preserves metadata" (is (= {} (-> (make (test-project {:foo [1 2]})) (merge-profiles [:carmined]) :foo meta))) (is (= {:quux :frob} (-> (make (test-project {:foo ^{:quux :frob} [1 2]})) (merge-profiles [:carmined]) :foo meta))) (is (= {:displace true, :quux :frob} (-> (make (test-project {:foo ^{:displace true, :quux :frob} [1 2]})) (merge-profiles [:carmined :blued :jaded]) :foo meta))) (is (= {:displace true, :a 1, :b 2} (-> (make (test-project {:foo ^{:displace true, :a 1} [1 2] :profiles {:bar {:foo ^{:displace true, :b 2} [9 0]}}})) (merge-profiles [:jaded :bar :carmined]) :foo meta)))) (testing "that ^:replace replaces other values (at most once)" (is (= [1 2] (-> (make (test-project {:foo ^:replace [1 2]})) (merge-profiles [:carmine]) :foo))) (is (= [3 4] (-> (make (test-project {:foo [1 2]})) (merge-profiles [:carminer]) :foo))) (is (= [1 2 5 6] (-> (make (test-project {:foo ^:replace [1 2]})) (merge-profiles [:carmine :blue]) :foo))) (is (= [3 4] (-> (make (test-project {:foo ^:replace [1 2]})) (merge-profiles [:carminer]) :foo))) (is (= [7 8] (-> (make (test-project {:foo ^:replace [1 2]})) (merge-profiles [:jader :blue]) :foo))) (is (= [3 4] (-> (make (test-project {:foo ^:replace [1 2]})) (merge-profiles [:carminer :jade]) :foo)))) (testing "that ^:replace preserves metadata" (is (= {} (-> (make (test-project {:foo [1 2]})) (merge-profiles [:carminer]) :foo meta))) (is (= {:quux :frob} (-> (make (test-project {:foo ^{:quux :frob} [1 2]})) (merge-profiles [:carminer]) :foo meta))) (is (= {:replace true, :quux :frob} (-> (make (test-project {:foo ^{:replace true, :quux :frob} [1 2]})) (merge-profiles [:carminer :jader :bluer]) :foo meta))) (is (= {:replace true, :a 1, :b 2} (-> (make (test-project {:foo ^{:replace true, :a 1} [1 2] :profiles {:bar {:foo ^{:replace true, :b 2} [9 0]}}})) (merge-profiles [:jader :bar :carminer]) :foo meta)))) (testing "that ^:displace and ^:replace operates correctly together" (is (= [5 6] (-> (make (test-project {:foo ^:displace [1 2]})) (merge-profiles [:bluer]) :foo))) (is (= [1 2] (-> (make (test-project {:foo ^:replace [1 2]})) (merge-profiles [:blued]) :foo))) (is (= [7 8] (-> (make (test-project {:foo [1 2]})) (merge-profiles [:jader :carmined]) :foo))) (is (= [7 8] (-> (make (test-project {:foo [1 2]})) (merge-profiles [:carmined :jader]) :foo)))) (testing "that metadata is preserved at ^:displace/^:replace clashes" (is (= {:frob true} (-> (make (test-project {:foo ^{:displace true, :frob true} [1 2]})) (merge-profiles [:carminer]) :foo meta))) (is (= {:frob true} (-> (make (test-project {:foo ^{:replace true, :frob true} [1 2]})) (merge-profiles [:carmined]) :foo meta))) (is (= {:a 1, :b 2} (-> (make (test-project {:foo ^{:replace true, :a 1} [1 2] :profiles {:bar {:foo ^{:displace true, :a 3, :b 2} [3 4]}}})) (merge-profiles [:bar]) :foo meta))) (is (= {:a 3, :b 2} (-> (make (test-project {:foo ^{:displace true, :a 1} [1 2] :profiles {:bar {:foo ^{:replace true, :a 3, :b 2} [3 4]}}})) (merge-profiles [:bar]) :foo meta)))) (testing "that built-in ^:replace values are properly replaced" (is (= '(constantly false) (-> (make {:test-selectors {:default '(constantly false)}}) (merge-profiles [:base]) :test-selectors :default)))) (testing "that IObjs can be compared with non-IObjs without crashing" (is (= :keyword (-> (make {:test-selectors {:default :keyword}}) (merge-profiles [:base]) :test-selectors :default))) (is (= [1 2] (-> (make (test-project {:foo ^:replace [1 2] :profiles {:bar {:foo 100}}})) (merge-profiles [:bar]) :foo))) (is (= [1 2] (-> (make (test-project {:foo 100 :profiles {:bar {:foo ^:replace [1 2]}}})) (merge-profiles [:bar]) :foo))) (is (= "string" (-> (make (test-project {:foo "string" :profiles {:bar {:foo ^:displace [1 2]}}})) (merge-profiles [:bar]) :foo))) (is (= "string" (-> (make (test-project {:foo ^:displace [1 2] :profiles {:bar {:foo "string"}}})) (merge-profiles [:bar]) :foo)))) (testing "that IObjs keep their metadata when compared to non-IObjs" (is (= {:frob true} (-> (make (test-project {:foo 100 :profiles {:bar {:foo ^{:replace true, :frob true} [1 2]}}})) (merge-profiles [:bar]) :foo meta)))))) (def test-profiles (atom {:qa {:resource-paths ["/etc/myapp"]} :test {:resource-paths ["test/hi"]} :repl {:dependencies '[[nrepl/nrepl "0.4.5" :exclusions [org.clojure/clojure]] [org.thnetos/cd-client "0.3.4" :exclusions [org.clojure/clojure]]]} :tes :test :dev {:test-paths ["test"]}})) (deftest test-merge-profile-paths (let [test-project (fn [p] (project-with-profiles-meta p (merge @test-profiles (:profiles p))))] (is (= (vec (map lthelper/fix-path-delimiters ["/etc/myapp" "test/hi" "blue-resources" "resources"])) (-> (make (test-project {:resource-paths ["resources"] :profiles {:blue {:resource-paths ["blue-resources"]}}})) (merge-profiles [:blue :tes :qa]) :resource-paths))) (is (= (vec (map lthelper/fix-path-delimiters ["/etc/myapp" "test/hi" "blue-resources"])) (-> (make (test-project {:resource-paths ^:displace ["resources"] :profiles {:blue {:resource-paths ["blue-resources"]}}})) (merge-profiles [:blue :tes :qa]) :resource-paths))) (is (= ["replaced"] (-> (make (test-project {:resource-paths ["resources"] :profiles {:blue {:resource-paths ^:replace ["replaced"]}}})) (merge-profiles [:tes :qa :blue]) :resource-paths))) (is (= {:url "http://" :username "u" :password "p"} (-> (make (test-project {:repositories [["foo" {:url "http://" :creds :gpg}]] :profiles {:blue {:repositories {"foo" ^:replace {:url "http://" :username "u" :password "p"}}}}})) (merge-profiles [:blue :qa :tes]) :repositories last last))))) (deftest test-merge-profile-deps (with-redefs [default-profiles test-profiles] (let [project (make {:resource-paths ["resources"] :dependencies '[^:displace [org.foo/bar "0.1.0" :foo [1 2]] [org.foo/baz "0.2.0" :foo [1 2]] [org.foo/zap "0.3.0" :foo [1 2]]] :profiles {:dev {:dependencies '[[org.foo/bar "0.1.2"] [org.foo/baz "0.2.1"] ^:replace [org.foo/zap "0.3.1"]]}}})] (is (= '[[org.foo/bar "0.1.2"] [org.foo/baz "0.2.1" :foo [1 2]] [org.foo/zap "0.3.1"]] (-> (make-project project) (merge-profiles [:dev]) :dependencies)))))) (deftest test-merge-profile-repos (with-redefs [default-profiles test-profiles] (let [project (make (make-project {:profiles {:clojars {:repositories ^:replace [["clojars.org" "https://clojars.org/repo/"]]} :clj-2 {:repositories [["clojars.org" "https://new-link.org/"]]} :blue {:repositories [["my-repo" "https://my-repo.org/"]]} :red {:repositories [^:replace ["my-repo" "https://my-repo.org/red"]]} :green {:repositories [^:displace ["my-repo" "https://my-repo.org/green"]]} :empty {:repositories ^:replace []}}}))] (is (= default-repositories (:repositories project))) (is (= [] (-> (merge-profiles project [:empty]) :repositories))) (is (= [["my-repo" {:url "https://my-repo.org/"}]] (-> (merge-profiles project [:empty :blue]) :repositories))) (is (= [["clojars.org" {:url "https://clojars.org/repo/"}]] (-> (merge-profiles project [:clojars]) :repositories))) (is (= [["clojars.org" {:url "https://clojars.org/repo/"}] ["my-repo" {:url "https://my-repo.org/"}]] (-> (merge-profiles project [:clojars :blue]) :repositories))) (is (= [["clojars.org" {:url "https://new-link.org/"}] ["my-repo" {:url "https://my-repo.org/"}]] (-> (merge-profiles project [:clojars :blue :clj-2]) :repositories))) (is (= [["clojars.org" {:url "https://clojars.org/repo/"}] ["my-repo" {:url "https://my-repo.org/"}]] (-> (merge-profiles project [:clojars :blue :green]) :repositories))) (is (= [["clojars.org" {:url "https://clojars.org/repo/"}] ["my-repo" {:url "https://my-repo.org/red"}]] (-> (merge-profiles project [:blue :clojars :red]) :repositories))) (is (= [["my-repo" {:url "https://my-repo.org/red"}] ["clojars.org" {:url "https://new-link.org/"}]] (-> (merge-profiles project [:empty :red :clj-2 :green]) :repositories)))))) (deftest test-merge-many-profiles (let [profiles (into {} (map #(vector (-> % str keyword) {:foo [%]}) (range 10))) project (make {:profiles profiles})] (is (= (range 10) (-> (make-project project) (merge-profiles [:0 :1 :2 :3 :4 :5 :6 :7 :8 :9]) :foo))))) (deftest test-global-exclusions (let [project {:dependencies '[[lancet "1.0.1"] [leiningen-core "2.0.0-SNAPSHOT" :exclusions [pomegranate]] [clucy "0.2.2" :exclusions [org.clojure/clojure]]] :exclusions '[org.clojure/clojure]} dependencies (:dependencies (merge-profiles project [:default]))] (is (= '[[[org.clojure/clojure]] [[org.clojure/clojure] [pomegranate/pomegranate]] [[org.clojure/clojure]]] (map #(distinct (:exclusions (apply hash-map %))) dependencies))))) (defn add-seven [project] (assoc project :seven 7)) (deftest test-middleware (is (= 7 (:seven (init-project (read (.getFile (io/resource "p2.clj")))))))) (deftest test-checkouts (let [project (read (.getFile (io/resource "p1.clj")))] (is (= #{"checkout-lib1" "checkout-lib2"} (set (map :name (read-checkouts project))))))) (deftest test-activate-middleware (let [errors (atom [])] (with-redefs [utils/error (fn [& args] (swap! errors conj args))] (init-project (read (.getFile (io/resource "p3.clj"))))) (is (= [] @errors)))) (deftest test-certificates (let [project {:certificates ["clojars.pem"]}] (is (-> (init-project project) :certificates seq)))) (deftest test-plugin-vars (are [project hooks middleware] (= (list hooks middleware) (map (partial plugin-vars project) [:hooks :middleware])) {:plugins '[[lein-foo "1.2.3"]]} '(lein-foo.plugin/hooks) '(lein-foo.plugin/middleware) {:plugins '[[lein-foo "1.2.3" :hooks false]]} '() '(lein-foo.plugin/middleware) {:plugins '[[lein-foo "1.2.3" :middleware false]]} '(lein-foo.plugin/hooks) '() {:plugins '[[lein-foo "1.2.3" :hooks false :middleware false]]} '() '())) (deftest test-add-profiles (let [expected-result {:dependencies [] :profiles {:a1 {:src-paths ["a1/"]} :a2 {:src-paths ["a2/"]}}}] (is (= expected-result (-> {:dependencies []} (add-profiles {:a1 {:src-paths ["a1/"]} :a2 {:src-paths ["a2/"]}})))) (is (= expected-result (-> {:dependencies []} (add-profiles {:a1 {:src-paths ["a1/"]} :a2 {:src-paths ["a2/"]}}) meta :without-profiles))) (is (nil? (-> {:dependencies []} (add-profiles {:a1 {:src-paths ["a1/"]} :a2 {:src-paths ["a2/"]}}) :src-paths))) (is (= ["a1"] (-> {:dependencies []} (add-profiles {:a1 {:src-paths ["a1/"]} :a2 {:src-paths ["a2/"]}}) (merge-profiles [:a1]) :src-paths))))) (deftest test-merge-anon-profiles (is (= {:A 1, :C 3} (-> (make-project {:profiles {:a {:A 1} :b {:B 2}}}) (merge-profiles [{:C 3} :a]) (dissoc :profiles))))) (deftest test-composite-profiles (is (= {:A '(1 3 2), :B 2, :C 3} (-> (make-project {:profiles {:a [:b :c] :b [{:A [1] :B 1 :C 1} :d] :c {:A [2] :B 2} :d {:A [3] :C 3}}}) (merge-profiles [:a]) (dissoc :profiles))))) (deftest test-override-default (is (= {:A 1, :B 2, :C 3} (-> (make-project {:profiles {:a {:A 1 :B 2} :b {:B 2 :C 2} :c {:C 3} :default [:a :b :c]}}) (merge-profiles [:default]) (dissoc :profiles))))) (deftest test-unmerge-profiles (let [expected {:A 1 :C 3}] (is (= expected (-> (make-project {:profiles {:a {:A 1} :b {:B 2} :c {:C 3}}}) (merge-profiles [:a :b :c]) (unmerge-profiles [:b]) (dissoc :profiles)))) (is (= expected (-> (make-project {:profiles {:a {:A 1} :b {:B 2} :c {:C 3}}}) (merge-profiles [:a :b :c {:D 4}]) (unmerge-profiles [:b {:D 4}]) (dissoc :profiles)))) (is (= expected (-> (make-project {:profiles {:a {:A 1} :b {:B 2} :c {:C 3} :foo [:b]}}) (merge-profiles [:a :b :c]) (unmerge-profiles [:foo]) (dissoc :profiles)))))) (deftest test-dedupe-deps (is (= '[[org.clojure/clojure "1.3.0"] [org.clojure/clojure "1.3.0" :classifier "sources"]] (-> (make {:dependencies '[[org.clojure/clojure "1.4.0"] [org.clojure/clojure "1.3.0" :classifier "sources"] [org.clojure/clojure "1.3.0"]]}) (:dependencies))))) (deftest test-dedupe-non-group-deps (is (= '[[foo/foo "1.1"]] (-> (make-project {:dependencies empty-dependencies :profiles {:a {:dependencies '[[foo "1.0"]]} :b {:dependencies '[[foo "1.1"]]}}}) (merge-profiles [:a :b]) (:dependencies))))) (deftest test-warn-user-repos (if (System/getenv "LEIN_SUPPRESS_USER_LEVEL_REPO_WARNINGS") (testing "no output with suppression" (is (= "" (abort-msg #'project/warn-user-repos {:user {:repositories {"central" {:url "https://repo1.maven.org/maven2/" :snapshots false} "clojars" {:url "https://clojars.org/repo/"}}}})))) (testing "with no suppression," (testing "no warning without user level repo" (is (= "" (abort-msg #'project/warn-user-repos {})) "No warning in base case")) (testing "Warning with user level repo" (is (re-find #":repositories .* [:user].*" (abort-msg #'project/warn-user-repos {:user {:repositories {"central" {:url "https://repo1.maven.org/maven2/" :snapshots false} "clojars" {:url "https://clojars.org/repo/"}}}})))) (testing "Warning with user level repo" (is (re-find #":repositories .* [:user].*" (abort-msg #'project/warn-user-repos {:user {:repositories {"central" "https://repo1.maven.org/maven2/" "clojars" "https://clojars.org/repo/"}}})))) (testing "Warning with user level repo" (is (re-find #":repositories .* [:user].*" (abort-msg #'project/warn-user-repos {:user {:repositories [["central" {:url "https://repo1.maven.org/maven2/" :snapshots false}] ["clojars" {:url "https://clojars.org/repo/"}]]}}))))))) (deftest test-profile-scope-target-path (let [project (with-meta {:target-path "target/%s"} {:profiles {:ab [:a :b] :abc [:ab :c] :bcd [:b :c :d] :a {} :b {} :c {} :d {} :e {}}})] (are [ps tp] (= (profile-scope-target-path project ps) {:target-path tp}) [:a :b] "target/ab" [:a :b :c] "target/abc" [:b :c] "target/b+c" [:b :a] "target/b+a" [:c :b :a] "target/c+b+a" [:c :a :b] "target/c+ab" [:a :b :c :d] "target/abc+d" [:e :b :c :d] "target/e+bcd" [:c :a :b :d] "target/c+ab+d" [:a] "target/a"))) leiningen-2.9.1/leiningen-core/test/leiningen/core/test/user.clj000066400000000000000000000043171343535564500247210ustar00rootroot00000000000000(ns leiningen.core.test.user (:use clojure.test leiningen.core.user)) (deftest resolving-repo-creds (with-redefs [credentials (constantly {#"^https://clojars\.org/.*" {:username "u" :password "p" :passphrase "looooong" :private-key-file "./somewhere"}})] (testing "Literal creds unmolested" (is (= (resolve-credentials {:url "https://clojars.org/repo" :username "easily" :password "stolen"}) {:url "https://clojars.org/repo" :username "easily" :password "stolen"}))) (testing "Lookup in environment" (with-redefs [getenv {"LEIN_USERNAME" "flynn" "CUSTOMENV" "flotilla"}] (is (= (resolve-credentials {:url "https://clojars.org/repo" :username :env :password :env/customenv}) {:url "https://clojars.org/repo" :username "flynn" :password "flotilla"})))) (testing "Check multiple locations" (with-redefs [getenv {"LEIN_USERNAME" "flynn" "CUSTOMENV" "flotilla"}] (is (= (resolve-credentials {:url "https://clojars.org/repo" :username [:gpg :env] :password [:env/customenv :gpg]}) {:url "https://clojars.org/repo" :username "u" :password "flotilla"})))) (testing "Custom keys unmolested (and :creds expanded)" (is (= (resolve-credentials {:url "https://clojars.org/repo" :creds :gpg :foo [:gpg "0x00D85767"]}) {:url "https://clojars.org/repo" :username "u" :password "p" :passphrase "looooong" :private-key-file "./somewhere" :foo [:gpg "0x00D85767"]}))) (testing "Pulls string out when env/gpg are absent" (let [settings {:url "https://clojars.private" :username [:gpg :env/circle_jars_username "ACTUAL"]}] (is (= "ACTUAL" (:username (resolve-credentials settings)))))))) leiningen-2.9.1/leiningen-core/test/leiningen/core/test/utils.clj000066400000000000000000000010431343535564500250740ustar00rootroot00000000000000(ns leiningen.core.test.utils (:require [leiningen.core.utils :as utils] [clojure.test :refer [deftest testing is]] [clojure.java.io :as io])) (def profiles "./leiningen-core/test/resources/") (def sample-profile {:user {:plugins '[[lein-pprint "1.1.1"]]}}) (deftest read-profiles (testing "Empty profile file" (is (nil? (utils/read-file (io/file (str profiles "profiles-empty.clj")))))) (testing "Non-empty profile file" (is (= (utils/read-file (io/file (str profiles "profiles.clj"))) sample-profile)))) leiningen-2.9.1/leiningen-core/test/leiningen/fixed_and_var_args.clj000066400000000000000000000002231343535564500256310ustar00rootroot00000000000000(ns leiningen.fixed-and-var-args "Dummy task for tests.") (defn fixed-and-var-args [project one two & rest] (println "a dummy task for tests")) leiningen-2.9.1/leiningen-core/test/leiningen/one_or_two.clj000066400000000000000000000002051343535564500241760ustar00rootroot00000000000000(ns leiningen.one-or-two "Dummy task for tests") (defn one-or-two "Dummy task for tests" ([project one]) ([project one two])) leiningen-2.9.1/leiningen-core/test/leiningen/sirius.clj000066400000000000000000000001171343535564500233440ustar00rootroot00000000000000(ns leiningen.sirius) (defn ^:pass-through-help sirius [project & args] args) leiningen-2.9.1/leiningen-core/test/leiningen/var_args.clj000066400000000000000000000001701343535564500236310ustar00rootroot00000000000000(ns leiningen.var-args "Dummy task for tests.") (defn var-args [project & args] (println "a dummy task for tests.")) leiningen-2.9.1/leiningen-core/test/leiningen/zero.clj000066400000000000000000000001501343535564500230020ustar00rootroot00000000000000(ns leiningen.zero "Dummy task for tests.") (defn zero [project] (println "a dummy task for tests")) leiningen-2.9.1/leiningen-core/test/resources/000077500000000000000000000000001343535564500213775ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/test/resources/profiles-empty.clj000066400000000000000000000000001343535564500250360ustar00rootroot00000000000000leiningen-2.9.1/leiningen-core/test/resources/profiles.clj000066400000000000000000000000531343535564500237120ustar00rootroot00000000000000{:user {:plugins [[lein-pprint "1.1.1"]]}} leiningen-2.9.1/pcmpl-lein.el000066400000000000000000000065041343535564500160770ustar00rootroot00000000000000;;; pcmpl-lein.el --- pcomplete for Leiningen tasks; works with eshell ;; Copyright (C) 2011 Phil Hagelberg ;; ;; Author: Phil Hagelberg ;; URL: http://github.com/technomancy/leiningen ;; Version: 0.1 ;; Keywords: eshell completion ;; Created: 2011-01-15 ;; This file is not part of GNU Emacs or Leiningen. ;;; Commentary: ;; Provides completion of leiningen tasks using pcomplete, suitable ;; for eshell. Does not support custom :source-path or :test-path. ;;; License: ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License ;; as published by the Free Software Foundation; either version 3 ;; of the License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Code: (require 'cl) (require 'pcomplete) (require 'esh-util) (defvar pcmpl-lein-tasks-alist nil "Cached alist of project roots to task lists.") (defvar pcmpl-lein-project-root nil) (defun pcmpl-lein-tasks () (or (cdr (assoc pcmpl-lein-project-root pcmpl-lein-tasks-alist)) (let* ((help (progn (message "Getting Leiningen task list...") (shell-command-to-string "lein help"))) (tasks (split-string help "\n")) (tasks (subseq tasks 4 -3)) (tasks (mapcar (lambda (line) (substring line 0 (string-match " " line))) tasks))) ;; OHAI MEMOIZE. (add-to-list 'pcmpl-lein-tasks-alist (cons pcmpl-lein-project-root tasks)) tasks))) (defun pcmpl-lein-namespaces-dir () (let ((task (cadr pcomplete-args))) (cond ((equal "test" task) "test") ((or (equal "run" task) (equal "compile" task)) "src")))) (defun pcmpl-lein-transform-filename (file) (subst-char-in-string ?/ ?. (substring file (+ (length pcmpl-lein-project-root) (length namespaces-dir) 1) -4))) (defun pcmpl-lein-namespaces-in-dir (file) (if (not (file-directory-p file)) (if (string-match "\\.clj$" file) (pcmpl-lein-transform-filename file)) (eshell-flatten-list (mapcar 'pcmpl-lein-namespaces-in-dir (directory-files file t "^[^\\.]"))))) (defun pcmpl-lein-namespaces () (let ((namespaces-dir (pcmpl-lein-namespaces-dir))) (when namespaces-dir (pcmpl-lein-namespaces-in-dir namespaces-dir)))) ;;;###autoload (defun pcomplete/lein () (let ((pcmpl-lein-project-root (expand-file-name (locate-dominating-file default-directory "project.clj")))) (pcomplete-here (pcmpl-lein-tasks)) (if (not (string= "run" (cadr pcomplete-args))) (pcomplete-here (pcmpl-lein-namespaces)) (pcomplete-here (list "-m")) (pcomplete-here (pcmpl-lein-namespaces))))) (provide 'pcmpl-lein) ;;; pcmpl-lein.el ends here leiningen-2.9.1/project.clj000066400000000000000000000037371343535564500156620ustar00rootroot00000000000000;; This is Leiningen's own project configuration. See doc/TUTORIAL.md ;; file as well as sample.project.clj for help writing your own. (defproject leiningen "2.9.1" :description "Automate Clojure projects without setting your hair on fire." :url "https://github.com/technomancy/leiningen" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} ;; If you update these, update resources/leiningen/bootclasspath-deps.clj too :dependencies [[leiningen-core "2.9.1"] ;; needed for pom [org.clojure/data.xml "0.0.8"] ;; needed for test [timofreiberg/bultitude "0.3.0" :exclusions [org.clojure/clojure]] ;; needed for new [stencil "0.5.0" :exclusions [org.clojure/core.cache]] ;; needed for uberjar [commons-lang "2.6"] ;; needed for repl [nrepl "0.6.0"] ;; needed for change [net.cgrand/sjacket "0.1.1" :exclusions [org.clojure/clojure]] ;; bump versions of various common transitive deps [net.cgrand/parsley "0.9.3" :exclusions [org.clojure/clojure]] [scout "0.1.1"] [commons-io "2.6"]] :pedantic? :abort ;; checkout-deps don't work with :eval-in :leiningen :profiles {:dev {:resource-paths ["leiningen-core/dev-resources"] :test-paths ["leiningen-core/test"]} :uberjar {:aot [#"leiningen" leiningen.core.ssl ; lazy-loaded cemerick.pomegranate classlojure.core nrepl.core]}} :test-selectors {:default (complement :disabled) :offline (comp (partial not-any? identity) (juxt :online :disabled))} :source-paths ["leiningen-core/src" "src"] :eval-in :leiningen) leiningen-2.9.1/resources/000077500000000000000000000000001343535564500155225ustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen.png000066400000000000000000002175571343535564500202210ustar00rootroot00000000000000PNG  IHDRVwsRGBbKGD pHYs  tIME 4H|QtEXtCommentThis is the good man known as Leiningen. Image courtesy of Loren Broach.,c IDATxy%u;f_]=N>Y0 vf!ReQa ![aCa9EHd; f2a. l/յ3̗UtLLur_-3w99~(G4':l~·~2>9 << q2<6 T@ns ~O63<C`/!#px @{p X ;_/:p$#P4 \ >^S RSaӘ ߳>@k9R(%ph[͒]9ZRᜄ 670Fqcu]w:tiw5GpH|=!Tp>|2NGuY^3z9 G8u8KKDZO~nXQ޲,nU|y=\yq|u=m82|WxOA|b{ā9~ zvq,,OLdiEpxTGGXXX$f3@*[;i3Jgؒ+uށQr-UJ!? `QZS?O˿";]iY[O!=gy_xqqO ,-E^٭zv71yڈ tov`QqEzcĉePʻ1Ik~qo%w'?O?al|gb ^. nUҷ_%29C,xg˼m|avMQJZ RVPN"O^7Jӏ/ewV`[m'D8{h{nL8)l!7Mx"&ޓҲOaZ)^O%9ȷrGgag8Gj'ta\y`C0\$ko_f.\q0~"Q3Ǚ!# CdelHLb `cMoOn\_._b%G">q _i"3?sm$b2Ox1Kq#MF؛_Z;ss|ok'(??ȫ?j<{>(J(=U81&\hr/Y a8rLz7a#*?W,{dk[!;i|-wF9Av? ^\|3?3gO \f',j(L4UA6B/_譪`qh!$b ,gHVن_&6]GUNmOWJ!#Ɨ^uH}^^Zӟx  puOd6y;/ :FtCɈ4uZcH!"iLhEw] ]N?w;]嗿JGR_A|o_sBqG~8sd>2խvb=^u)G X4:f}cW6ֻƈZS̴jU*f47h5:.ۛCD4RfZ5j:ZDKa͕D"TZyO9 ^}"v]C#_ۢ$RVsleqLٓ>c7VB7fŊZ5&IGk]z N|h%^'BXQYpGnh44+tw ")_79wt:_+f > ׀V@gT4!֎ǎ Ys +e:=qıfaqv>⢩`$ȃ:MPRX]orcm[|;C@G%W^1{>~tOtq,oZHO{KѬii;1x1Dju0 +25sVt[H%y7RZZ="#;./4+Ša-zC,ͭ]wg1(W"R=)L@V#f[ j1ބ\z}sk1+K"5f;;׳ ?[Ny}ܨ XJ.67q4vG9<rzi$%xK'4`kKf!RFJ9-GYߦ1L))7o k-iTDDTZ]zJR"헴Xb)U*R*XNnp(b i)"ڃ& ,fX'hU#͘VJY7<N1:h1'8' kNy^"οu<5{}fu_W(ɽm ws כ%/ SO`hɠ+$qrvwG5Q8бon7iT*P8/saCrX}O761e*ZN߀1uQǚJ7 qU&Q Zީ ))BhD;7F"c +ŴXݮ6;{q]lv0Q&T q,z26q?;K=2G\[e4u;|;e8*R&/x_AXk{*YJ 3|S?/Fs7%ޡ;[|qt{o"E^RJ%fvLBVA!K,CrHXJUAk;vFcpb1ƕ dZnMžZ`Iyͫ8UZ4jX(|B wޓdWG g-D+D&S Թ6E#G[u[DZam(AYcx&t,@h &utإ?PHeQjl'4hyn1*OeIXH|w *\](KlZRThi7k45 )4 3+ G=U#D)7f tPNJGR(q$jjJ"T(Q(&3&3ltuO1c^c`#/X6<$9@]hd HQ~:E\9/ľ"K;R|CuׯOvv^ b7ǟxc]z-D ?AUS_SRf*-fKַ-UbN CVW`TDZ3ӪQ%#n )䲝(I%a .j&+h\pQ?s|=`DXiiCcHQQZZVy`qR~IdJA0 $’bR\B%ɨ*cHSr "q,̶6IbH`|~ xlwoN!v-ƳAw0_jē ∴'Ǭ]G 0'Lŗ>`ˏo0Rs̵:q̙3gfIj5gxG|:!h_km=K+'9rD cKQ ͙d?<,q9sr>]ᔠ`+ MW=!~K N$w _xԘrZ2P6+'lXE8espa)g3;z\f IeN38i_HP8Fm3f{{O!! Lʠ14lt ,/mR8Rdy+` Un%OOEtzݠYKHZOhy9T1ժ[5Y#ԓ~Q7G%ɯp9%X_V7p"Gl#GbTBD'ƅEu` q(#E:*Έ[@d' ɭipW{*X\;;w- 3iE.8`dNxfB,|c.\X-EkluGtzǖ G:"D"%YVǑ9.ycϝY䑥VTUD, uJm'lRP +V@Y];. `nGDJ"fU1\Zd)l2JC?[|;ߛ^f9X߇X}|;XXXn.RBl*8SXޔ1?XLXdww(5(eT+1ss $O'7>@ņN-O@GPoTiRWȬa84ԏRll9M$K.lL*X9"8Mj;plsz6 ;,>şn iALͅ(a#ro>,[O; *a!\Z1y^YAtf0@ķ)SMٌF &5AWbv{K:ᜣݪ1?[/XDfp[[؊g9rԧwϬIyM=Xm%HOH!+TE llR &h9\B9D^U5n_kXrꎏi %HijN"_ZNυM} v5Iprylt_^W*XWhע0Bp3綸L85Ggc>Q ( 8. xUzip[X1 b[] SElP$q(ȴ"N<$O~u3͹k;_3 lMhƚ뒧ESLASz׶nD=Nǰ7"s)Z$I.]<ϥ˗O9 >q9ak Jgpq3 G4XrQ"B1W|*hl!Po$ZJifQh 7(UnwAGܽ k˥N uܚYg}$Ѩ1W,s,kDb1xN + 2J%XoHCFY6q8 #u~9GJh ]"tʯu,Qvַ Vw- XfE-_+A :L]#kBzϲ"8Z6El,6\Xa}{H1YWe š45=R9^kj2摧֮_፷,?~20;]" ЃgQ g e]e}[c`gKiilijC%H~NRM*>d>F"3v[@quu^oE g|tA/Ѿٗyg#8sdN/Ӫ3:JJL=5^Su,vgV"``c4t::.I^ - A;! ЮŧWqywvAZ조n+:<'{BV"DN{sxdk-suТ&!:V< ?ڠ72\s~Ս!qފsQKYOYD ֍/Tηŕ,,TO|UR{@K̂w ]xS!oc))@e(k|}Y e[MTX+lĩ}y*HIʛPȪX7 g9R#ofQʄ\@+c3eIŅ6? gN.2nplv;;^&Ɔ0!, H4 IDATT"ȉ$[1D#LA: vvv٠`0lq<+lxGTx )\Y}w 204(Ƴ9R'4c|O\pqHipfI?Ք׮l;0 |R@g+R׽G:Z>W!| ].]5 xt? %nN8UH[$sѤ "_M{NoeEq2y:)dNa:͹7٬ў0bXez`$AQ嫕 }f\gHQ*fq#<Ʊc j[^f˗v B(q%`E儎N^EH:$IBՂVȲt4bkk,#2>noliĕ3>'l]h)>2Ǐy6Ya+*yjpj.`\D/_`iEmΉ21{g4ת O o\ʵ.N*F\V|{ /Q&/_`y~98FiXkӝ.oz1HDlb[ .[_ ?+S,,-΅2†]a:c ,Fe?) IqVv17Scyq(,.͐e)bn7+rfX6}ԕB:Zx mc;v̫.ڜG۬;soz1s +TTKL^/X1FZʱxXz7q宩#7(hNϵ95bg0`4 R^p;lu qI!ڈ%oV'8loocAGcb<KlJgSfxhk޸ͥt .g]Gg{ y$VL4eP.v?=8 |GPUI@tz)ۻ=66vH3xD4fw {62q2)C'S#h0x  \nֲ2XbH WV;%‰ a]D4ʥX4{(ϟYjr#!-Yg%†8NjxCϰɕ+W,,XGZ ,$FG9["n2+JkEkMk2/g}}7-_|X8ڍ{6<8sX2ᥗ6^qg<4;3g9w\$CK ('#䒭%I'k:RcoyV>78o3s̷laXZ4@3@אwNa?'̡Jɜ!dPm Lhc]g-Gr ׮rꆏC/e"1nM:m\Xdi>13m]%ƉA(EFB;x 'p"J Q j|ɲј :EGP95}-.|{ŵkXvh]W`M\uy9GgVosq0s8eG'yJѬpV^_6PRx%ǓqT^(sƀo_eu*\{#fgZzI0e}idtD_&WCj9j"R.* JqQ:X$ٔUqUFiXNyP,4`>Np 7vr}׋v3m(c.N,<"j>RĩV|DVɂ7mEӿΡU4.#6o2=Cw@!+l. >33sXi9b%r-|gwγwܛ7 'F|>?Ӣ 7GxՍ߻=adsggOg !pR{WܼHLtݬ)#mHc,Jd& 7AT]m?dfCoTbLf rNPWI5;] FFJ?sDe#c14j5~O|yg~vݳ!q.6ekTjlsq 2'묥)x+0uIѣǨ4Tj f,О] T؀m 9eonDD(!}&e*xw#TY\>B li,ia3&UӜ^YV5ZR$q,pHU./w 7`t|K_zW1qa&~ %vf] IJ{zE-n"  t%dp/RWh. &3I>xO@ D\Cg' 35Z&κBHP (ve>W:A\XƺBaLXRf2[_L`OLFJ[^„Ų.V2lff>o O<|Qq.ZYoy"Lh6/,1Dm7^˗.qETxDB݉+B~pN {9Kǜ:sauƄ[H9mgu ?LTē=8cy?9\6n9sZY*ɸku.6h8cuZ\]k \śW ƂR "~9lk<m}=9Hy;A,S!nT6Cs K<ē!߬x  9*q:D)sQDZVkPfyǞzy)+7Jp$ z#`D#4ɚtghy nA\*psn)Dgv V6SE[篼v~~( }WTy ,XM yjGB3/̴s/dGVSk?ʛ8V,.-c1~tI ;1ԴK|hھ˕Ҽ׳]2R1f4?/W v-~MA&"/K/@dЍ6x@R+*[r ;#K*n 8v&nyzډFksET"2V7]G=Ш8~U>/,SOrZIcox|DȽo`MXJǟxv+ #,ω gyXՇ1AG@P2[+\(xAkIw$XcU3շ]^d]wv/'}վLƩ,2TEy4#!5+x5$ ֺ]rJj:ޮ5Zj *g]&X;^|Mq'޽ngllmc=WA lEN/'\_ի[Cnz_p SWgEE f5*Qy[Eh]ԭXmJo@t-Z8R'A!3Vv`w3Gfu9z`p}qu dbJd+ 7o/ߏJ{ZeH#GpU_8$>k*q!/]LL^wo 瀓+&*])S鏆l201jYZXV*Dj 8/,򝻅RϦ(J/Mxo5mPb}'"mncpFٹ 9/YCuR9}NfnuycpEQ̃7^h"B-RtajA;"o/"NQ@I5 5s\i&v=$,. Ghrπtz MbMFi/}AkwW;>Y6=yp#@1?HR+"Zog)=z' VSM PAv/nOg;EB{l+̈́`H xuSř=Z $}X%wQy+ԒJavM{ H `jդ7rDDr$`O9爫-_@1JI+RjZ@ȈQ9@-?9jFFAiVVy/ ;YeJkZЮ{frw0d][<?jNtcVG:%29.cgMa^rleiKmJ =%~U"c R{@lf[fDJYN  ytW4;<>أLtM:ϦNϜ8:VCqpBL{a8<&g( @Lp3P>hWn=mhf UܲА*y/D|05L'ܦ-p+؝.}WHqH sMnz#,04N;}Q49] c n%sm̖_:8 @|?PJշ SLoe~>"RtA:|{؋KQ'U a7W^Ĺ`{kް[ಇHɺMfŖ2 ‡?G9{bj?7;1J6<'mjq9^ CB6Mѥ3ju3Ѓ+O=-{@HVvﯵp*7ְHQ7h4Z>QTH(nO'[tﺘ~{MƑ_fe<8/~絲y*~qTp1 pߒV10)Ƹо:|,?"SsZKQ]SMXFOLm4JhT?L ,,̅btGog7]-'IL'j5j,ZJ~`!'FwR\ w ?t?19|m4pkAkn(v9`4 lY9Ǡ?e:4?H|7jU|j.33ĚclVa0 aľMdvvVEZM̃7R,\ӛٝXq?t8&MӲK}U; bTzX)D,΁YiOBVc0_L֠i\MA><[k@!35)IEt6KvX~ߘjB{K}a*˵~g{YKM5o nu{]B/W`m`3\4х\fm82n<Wq{ċ~ctBGGXw<$&7<!o7.cO=2Ku?["Q\)Y6sJk4*C?P,Zk06X&`,\cxL#,wsZzXQ@z}݈slo+/k!J+}hčry8Z΍]:*#4Jr((>º?8ck4@:.0vպ|s eer,Ψ-8ʷ΅Bp.a8ruv4p1Щ w:_,1ʝx$)5;w{n^ghT3j qTuK-guxr,hQ |O5RYQI˞ EJ%XK`sp{7z7OG^$"~@n>07;mw["[xy`_c9+8c}ى,C뵩p⒉zejuweC5YfG<۲3 "Oyq4 wz/XEJ̴.l1|M <~|=_Ǘ? v(QQSiw| U gxmeD2 ͰMR_G_#2eNh9o`T {4+D` 3zAp~й‰Ţ+C^C"G= A5.nmm}JÏE q]JPl%,z^1;Uu'h$H{;D8I'#0g~3/*o\*wVvmx-}E<^8xp9U;Jw?k|8sCm.i H-* eՠVaEj{q~ }.5;:3Q(`pZE i DZ1\qwv.wjǒ"3,oX7I_OK%V)hw,+2:aKHHrz‰gO-4; 3%e9Vť# ^JjC?S0&sUWfi`cZ"L @* ]ާ\:[FQm]ܛYx V h" *9jhCT]\ |VJ\~7ÈVD{Oq;|wO# F TlSXq焵H@Ē!N`~{F#FIu+M3>ZL9D9}{s+8980$I±'J -!a/)wf,N]Yy5Z&cwmAQ'y׻'aƲZrks흹pk JRVv@_;7c;~5'Odee;PŖB P;b~|3_^i`12)kV`c1W8Xygf`vZ0@ %aVxwh6C'ɜ[(:CKo` F^b8e/ IDAT2Q.mF!k8\|n{G1Cg9rdgNܱ?9*+[;u1@,$BGhbj2Y>P>;l{ E({o(s0bvy2@iO2Hɝ)/EMݵXӪ֑HB7|巸ţ3[n70Pcbq"kܼ`S%C!L:2d>NVkU8vվLԾi;#ׁ#YX (݋ŷr1NEsO+3 BmGoNٝvb{˳suo[oePEJ K$;Nd=  a8H^,@ؒ'bRj#Eq(re3==~,y8ުMNP4Xͩw~w.ؕ~-UPaFG¸>jN0N"q8)q^6οbEdCs˿j%h!/@ B"Q$R7a~~ۇX 2y sFM 㜜AKqn؀a8FC*>N8#Y8CH a6 "'О'*MeG1_7hSOǼ->VĹ 2܊4Qi 8NfNG`*r1!xv$k:49cmŁ%P{66!6" bw|[QDD*LCPw NyLB-7`0qppZסv${njY3G8(f;k+҄Ѭw.^6)W^~k847hypl'z!ȳA#y^{)RwKE^/韜WPz7 ş9 Yec-g烘s9{ yZ:>q:ΝwG^ zVt%anLԸ pʸ"xS. wbcsܕ;X?dkuB'Rc)? &!T1 ci-t(ܜ%i$dDt•uutQ>+'U]9"|\bwxJ_gtӗ@ V;l8Cn,u/@O]l۷y/MY~;;"M[kݭUzxd8kXd7r)ExBp*N gOCqLfbzi!z< .vw6HȔqg4Ƭ,&D 9wad)e1Zj֐ZAЏ+s\YYl{HjQ1?~?zu&e(ŕEh<Rqy-1ӱ'i%مηw~ai,-qqx2 /c 4s_('>ug J(?rV-kIiS՘M2dY1{2 Sph4`8͘U+43gX#g#n\EQę.j<S8O' N'X'e%B\m@;ܹ gX\vJvAy7~\=kK/&BA~ӏ{N^:6V'R)5QAV-awk)@((a<-F$nGs<r瞼ocG[$bME9pQV .h2L$ǥN0r*bkc9teous؟A(/4 M<[X6VDC&;G|$`4*f_{6L4j3LeQJ0.*GMSY\Ij% XnwB`l0o7SW{/Iwa]5q" S%±?l6Y[[aeyaxg,_Y/7'~Lp䘵QJ/x4S&X^Y$J 5L>+yMڛxs8ƽ:nu Sh$urK[cww'O܅(*3Y5fS)XYnQ Ӳd8 `HAxO#"G(PVkSNS hzZh9LuʒJEW7U#>lTh$˙L2.4մ5vm+_1B*{k3t|Bޠi@W&8&h[yÏAurQ|\Ku;wev# zIGQո|izQd"[Ҽۉ8G766H4֣do>}3xSip8PQΊ 0jtKK5Fѥ׫ޣ,Lf 喊 CvtQ鴈$,MDGִ >Y88H$/z c,z~c@(?qhz,cVUWdWftu굄 Y{wO;a#,^j,U($ -&V,*;u6<_ݻ;1qgPW2JNx1ayx}圡~/a H͕gC5WVB81L{oT$=FJ1wr}&wL)<'Qwa&B tW`y)e Xitp!@C.|(咴l,N ݐ}0WXH/^,v AIxQG'I>՚ n߽x~9>[zqof9x4!QV0V$RIQ@d0c:Θt'91ChsfXVEJjB/m"0չ*̱(38>ӺdSXi.<&)'nZJ7Ms5`p)cVzQ&؆v(t(T\Ʌֹ44uأdks NHL%Hjʲ2hJ5!')xqA Kox[NXN?6弜6u HL8K8NR*g|.|cBH u;].o@嘋^}E7 UHZnr` " zYr G9TGQ"_8VxHѦ֣ EeJ3. o:;NU9;A`489iJ(pV̦wy4c<_x;ceE=k&C_NNBj?܅?28HɒLą7<'6i6Cy%88sopPPVGnm xE}2JY@#|x/ RD/\Oj;|Zv?YvZndx0jh>\g}!XHk+۽0S|Wo"sXLB {Nf'ӌrN|Y9`Q:׀u ,e/<]**eY*L$ ҂H3A9t '9<5W8cC-\<~orCz'QyGQ ƔL}Xsf9 Kx5&,n+bT/pErDzuLPZN0Н4q;V j BӁRkԹBP =3|H#ޅaRXO)4w Ӽ ߟ߭;DTiA*SyŃ~f-asGed0&5)z&mR6OGOKZ-Vc dek`21Hrn7o>WNOq4`NC$dzJiN3J7mMs{`oާZb5sh,` '%E2܅q|YHȩ$T>M]k&!] c@W;ŋA_@$rgF0YKA* ;Mz; ~+m v>\>%y8xyoD;('d <^d(k-"yYp2N Fx! 5hce|Z1 ,znR)1ˍ=E&B7!5e L*\h F9AD k6.&q7R,EdRi8sSX٘N0Kg~$,L[# "lN@Hwj}\M:Z;ܹwZ4",^gWx*S ^`pBYJ,:W6d%{Mť%^7L.̫P>JڼXTJ g;3F">9d\R1*,'v;a ǧc,px ۪Hy<=W!DIIa㢤^b1uG'`Mxy.\z1è_@Dxߒ;i촑u04gHYV949/Ow!αg!.yx.*H,0f>"/UhlqݘvߒƱYzrzx>zN']-?wr c\-Ҡ≎)07!"?V ZuEZ$'g? o؁3Փ%yX0&\pUe)X\vzSVLs,Rx:eUGI>PT$g!1@|Dyu YZHc |V 8T(MD62'UsUx IDAT".$F~>% p>#Q- =  y1? tBixo*5gnz"QNG*|k |B}ALf`[ípc;J1hxX6$z(Pki7##x/ҔBqk)&刨Cu &z5DK|eC?[ RNVZI(۩ SԳ?ʹ;IJSw FUp1&qBXhު~8=/e 10 +&D%BHO֝ Jc/>sRZ up1)+8pM5R+:_}ʃ12=ڿ3U.rދ 4/::J!1GR]{z)qm':)Ԉz*8~5 f%$wFDbܔĠbV& $ Xʌ4̲Ys4+-Y$$a#/I#xXkJ&M˵LghoWvEVԤ@%T4b lTU({Q:P83HhTEj-T3ǡÂlQżrgk N(\md(7ŊlsbU9SÌNrF+ASuZ#ZlltRcUJuۅ1)`>j9!h0:=bm3R#OgY .!!,QEY'@`+$U%Ki, Bdz iտlR.xYlZQbE*^b!I;UE0]"! L'AgTlH[i(UR`hq! &3Ǩ4i`DVJƆ,2=Z^Y)尕ԔS|WJicRqNq\C3lu,@VhNgX/.\iF'졽%˧"BUd5y2n`W^zޓ C-M^;ԔZ dik#ImFi)Zx!j8R%_B*I,,Gsyk;$iE$ q~.nj"(qVSxVHn[^BInJ*"U`KS%e%yiRϠ),m/&I@S[`ÀNb OBs7 9kois5RRJ2?y3jƢ$Q'!vvYm't)jHiݶY @T,/21hU`@HcҰJY)+.sBGУ)S!{Orӂê{T ^cimoK/pOG1?S?F_/}a7oC2uQg(RC][(zjֱgR(Ka#,R(Joj2Xjm@hY^^l67 α۔$Vbct:?C f,͘>!MpJy2 &.h~ۼb\y f;;;HuWV&'WLZO,bxsysյ.ҹp DKF+/{Wo0Y[ƭ|O_>I{䟒7~Ѵd6-hyIj@ TO)jl{&"؁jz )fkLr2/… A]³fcc5Y>eLs %HθfS d=BJ{OX m4I!O^||?"3y}yO}a+oZH-]p;Fu%$Dh*Mh%?W*rhCO*Ź?!2h.'zWf2ZIf=wO~ŪڹJ}\%d2cVJ38W_|{'0ōeM1/rxwiqkjF)"6<(IDc8{M&1 ÌZg7iRq+7Hk*Lw4_kll2-Jl(1ddbIl826֣;&/SW7~54B݃g%ҡ^ Ddxka$KؖɇĜ^PD}8u2 BSk5'>W0 4c&o߆|Fc3˘IX)*Ixb#=䈵lzNo> o@P ?Dh[k=* W8$I,S{T)EDhQ{fA.dx{\9*9f(bIΖkxApKF3KJEyOo.8 Tg8-9<i'g7u̖¡R_b+qu=IZhx=d0xVoG"fz# p2 5`'㳿O͟77a (e ;GzWX2 D\C}ٿ{{GC 1{6\Jwu%T†UR?yۥ,^@YV<8tr>3N q$lٟ86◢d.sm=.`KHP4`p [*QXޏ?[q AxO=[/%(޳KbJ X! ,}$2}*㨩7kU{2'&]?)hl_Ճ׮=I*Sa ("q}aȓ(pUBI>3:-sW(议w?`6+r!+~2i.(ICI\PV ~֬ +KZ$I.xQz^z&l^Z/JxlמB2npB]{\ॏ?0x~%v Nۼaq=P>}~`gpRF׺EIJ6T !,^TxYZ,.G,C+\臔8I|)~K)v-QIH uQ:+.GX g\TRǛ#fU]D Kt.(N菧*w)[K)sCke$*HWZƃR<{N87iZٷֆQxCisO)G,uC#BFƓM3f!&xLy`b򒤖 q'Bp˅*jKhkO4c!}nV^#H ˇ9;~`{ ;v޽§>aC`-ʥ-=R(bx-Ik'TlQoFV;x=O~.6(AZ!Ϝu}X{)$ؕ"ף"O^!8*&B {u0cx(gx+2KjҲԢ?(b 4?c.%੍ *B)"Hh18S3ɟiB6>S,+: e:p%ܓ,O{@MFƸ,KOO{<(2zFgsP`ݟ'[**[t:^d܅\y O?A"j}\_+Z1jv_?$Q-ů}b&eoG >K!6 ><غFI~, k8!xq!(*&45:&*7T#p>xp*ظHx~23nݝQP2Nf+VdԜP>.GUmmc}33*A:_؁[(eQp:v 癵&Ki8b _/ /ߺsEnߤ :.^B"U" 6\Z>,|(pRNGI6X٢/lQ)ion{FX͡g,=yk۴Z@xfٔdByAkZ$[I y(22aШ O_ޢѬ1NB6CY o]!7O5ke7S!s:x uX4gYj=ϼ<@eRMzX0C(WxsG^4,CuO+X ]x>9=ٝB}6~ъ!(yiMqnBgyVXgH U˝(#i~~kpi~#a29ʑh@rG͐֓&'(.8*!PQ,HH fls'c**|/«3 ,NO{ZE]3($\yo,=R"HFuR5yC/pL>y)C^gcKp?k@$z׎>w;hHvZ{/Z>WoNs:[__~&<{m-#4 H=Z**İ;^r][Fg7_zOr+@ SFIcŻEv<5p`̬4K `VgzuA8͖сifI ^{zt4 _98!j–0(m,6`wK(%QB/Dng*1fX$)Xe7#X,t;Vڠc64)i.[^\9b}< vJ|S楗u%8n_== {'<bfݵ"<ř|{~ ^huǣ FO}ib'd(´|XPjNy/xj6^"0e$ڹ7SY*iAv嵏R.-ƭcNF%d̦hez^ZEʑ02aWv|gi5RN+e;5Ji UauV픕5"dfV&HoBlMftU. Rfn;(E E%.]Rq5m~n"Qz9Vdc>dt!fmc}xgכ\~I\d2A14[̀R{az<7ߜ-&݅>g._e0?:W 3n?\X|*.$I荼(ۇ~߽Df ZG_ͩ`c80<bllS~Og4{ ˮsιoz_g_@DK(1#J,Ɏ8SYY*V";JRN1QT%#rU[%EI@egz=s}@̀ҭjL7u}m۠n!J)V9}> <9"pzǸf:(r9r F{=x6 ^tZ ѨqꂇtezNyӈl]xH[2'+k -3XfX( |G= ./hQ`m:_ƛguLBJQ:i9dc0rm0 !JQW18 ϯ5x{~r]&ԛ넺C k\,llWGL.KgL\.( Lfva"MX$&ZFEݦ86k-Q_pɩqW! L#3h%oX?K/HnylO IDAT^l{3]m~ Hd !|#K!jG2D [NH*2@[FpԪXc8qp\ڽ5Q+d3C rέqyE[q#o r<"Jg?~Wi|.wG׳0^FIBENZK915gri6,9 299X%2Jka;,}Z,ڰ*v:Zk5fIDN! Ä G<E>!&[P*exx'bt~)F( |[)Ԣa La*!殱M=Zx;mq#J -9޼0!̌'#s rm7*&dP{g0]/}֏|rm Z:$X5]]1 _l Ht,OVnw^lIJ6^a0jCJrAЁ yN)##qG?j ~׾nHq'8nF{i$@(N$9qdUPGB W]0wʐ9q>NdžY8qx᧭aldɊ7@!: JI Ej!ؐ/,96>gUQH"䒟Cjr p0"R='^:z\Ŝ+:r361I<ڋ Aq!yT*%&CEk \2K6}E/(u&rU8i(CI Ba#qpqFnm܉bD Eb1` lmVr䑇?\`qb^Ά W5:H$Z]t莥Y to.֚3{r&/fcVB+PE8ۓhH;@ԞE cBC> 7n!x`7O,nV,HIcH&֦(]jt h1Ulkll']&_!Ictɾ6v,--X6Qz!>F2dQJ!P(1X&#$ɒ:yS!BY8yO硶/M^Ts i^o[J&0a$$2.jygӆ|9.C7nNvݛol QdX]p_usx|6#&#l⦧1=pddYvB8l_cm:)dmyF7fo V$H_\#O|#x0J<9TWm[Pİ/QdX!-&LC RiAhM+\6+6Zx1Љ[9…['*.HP'LbK [%"v>cwJaoo-?4djj)is,/'S1?@ -24C"2ף>׭jvvh<_/l\riW뢝,NWP.{Dt}M!rK^$J:jfkÈDqlRt]q\L!l#,V֖>7ġCzh2gysLYCgj|ͭtz׾y 2$'d{n^ݵH{hc-B/fW#O{@F'ރBhzrFG0vmn/z*?$oY^| >-+LjN?#֚|i^t1t|vϋq?.`>Ck~I{bQnur͙bct" l<]E/ \;|H0l7{΍~=\tTNGܑCfrx)![(yߛG:ԆsoΥ H%r(J7pCӣ 8˼_8MZNW87p2PȒ 2L uD' ] wtURFuDbhp0w;6.]N66ɍctW SOZp(WpE/yHjЖH%n'Cw+_젃ݭ"6ѻ{˘d<.1v[7􅫍ok!"jVl{jcds)xh5VaIZJ=H\=õkWx75EqDǏpp;o78߼̍ o%& ob&tCJ%}M7&i?1hriHJD}NA\`@=ikB"1b돁*O{H/`fj2 ͧ|mdN Z2?C(`g6"oXʏ%u=v-vå?Fa ʌT pjjxxh:&&Y{ ? a`MSO13ƢX5Yg:~byƊ"S{=omk%b8<~nHmH'̻\Y%| H:&9M ڝKj&(c!E>=/^3^¥+ \C)"kz2+rR،Zddծ FH' C ]EZ8+xz kov$U035A!uX,..飯~zVWo1:칯 Q<3Kߓ#G;= k / #3V`sbedt q?+Kl6"V6h!R6)Hx;61IZOF]-hUGڞHΌ^dX7[ڲް7oOpڣͤ<MzꫬiV?4ԕ6 \feu/KA3{ܸ׿|Uf\4P`l_\ݯ"npo/>[WUf"i_y\b||!kf/Ӊ3HTYw>z>1YEh UktRս_jTm'~HG*%nZ335$X?f0Pw6;jn+&&p!Y^Lk,-PVsR1?r1ix ,T0cE_+^^"n5CXb^̯֫VQR Ӽ}$?s -h2N8&!*C((|%:Q*: ˡDLc;6Z)veNs"%W,d(V.TC#<LN`_존=?b(m߭2À' s+<J9Z :±KM&,^<{i(LUMx ګunky v w߰|R|.6hO ,!WY-Zu(С=R޽hy a׽#cJe* kJrS8t:r Bf|ר5/mZN_[Wdj3hw:DnKף2r`8qdr9-lTNzUD3ݭ%#5Li PJ+kudxwhޣC߿1%(=:×!$\K\t_;\7 CJd>z0la-o]7{J1Y@/塘GN .W#^_FR ;OL %Zlxop…q{7\GXwk_( ~DBۓ(\ vNx{T@2%@ڐbWe?83ׁ_^ ytޑGKc, 90 CNϠT_}mZ2U8=ZݱXѕ?V rE!_L 뵔2AWVg}/PDݪJ)*ʎCf搤0˞]QaQ&p %塓O_M~Ny7!|_}bQ>Ḫ ɓ#L"dSPDJZv#"`D+Qw@҇i!BQik!*1_aF$Ď/mt #SX5:<-._NnyPGwK b.͸TH|C)LȌ&~]-j=G?_Ur? t\agϲ.T^g.V́)+%LO#e@_݁]jP2}he6bqe)"w\R pC%}lRJ|ʹsz<) {7IԸ5sy;[0|1"$&h~|Ÿx\\W yvֺ:&{Kfap {Oqiq:KdE#R8m"tlcǭō<Ƥ. IDAT{b>㦜G'<k5C_w ܸ=^#5%j6)pr~FխDh`R2J BG?~8Flg}:}e}*8NeD\0UT %qP*@gt&a xM\Yl5#~ 6 շw=J5:<@wtRM ?/h4ۓY,]j+‹3/>ˋϽȋϽVؘ̇ nG +#lGoSo(DZO`!@h<]7H1Y 8ggtmW..sl.y+dKݕEkM(((Gf]_At *gƸ|ƸM!eWKWY]]ɓ8~QT{f_ȃ&f2~"xOclZM |X D|~&,V(]`"I!(&'YXXKN?ֲۚY3ҋ/1448`zz!vE]ʚCQdB #.0ͪb޺aE-hT>ל:ӈ-68_8^Ҋ߭k.P A5R|#<7U7n 1BHżՉ4vH^! >5:8(P5>6'NX< nWY56[[ۜ?>jQפB䎊n,ha~Ac4NztjUwN}e1Y^x*VGԲ}8H1([)Ns0Bċm!h!6 @%2bJk{"!\Ϙcr|'׋ej6=9H7R幾ciˡ'*]ߵH[FuWjl-P6/mFoqmj02o\Za є!gjr/}Re18ؤ\:gfI/wAD6D`3hkby6aG]Q[L M!Lj\ 0[׈k!T7NQ)+-qQ8 sCb33:>@=`v5vn@1wS(=}Ʒ]F8Ġ s<7 ` %k>l[_~zO{epChz+7Amߘ peX/rQCå/^YR0aP։JlX+H*бI1^zXƑ" s.PT96G% yls O KxɥFB,^G 6$_B'%,V݃2drtoef{k,FȤ`k=Y:Q  ,QWxWY6ڋoxJpkFbs WYu}̮v![4v!fJ`d&)k]'~K .'iUJ)=?LE:^O&p!N:CJ?C\~gz5OeWx%r'=l4G ۭTfNu{;7d]w&p@n٫(G0ϯ<( 6d&:٘أK\u,+uzƉ*`CC4 "dz2BbJAy]]Uu0>2Le 1.I[Oq,d$L #DR(N#"^U[lI &M9 1аs9^S@bˆ9B.B]c:E;خz_6^ p״a2F* .lcs  rmIkZ aLdq~]XMVcCTwq~2@٦q%pZ<Ha{Yw$OMkIKk$ -܉15a\1L&Hc+EXj[>kk4چ)j]~{1`p_ 0|P[u~TZTk+@S5 Gjۜ_n1V:t X : V) 䳏Aes e><%b.jͯD|Q&!l(k8PAJ33ɰJ^~uM郄 wx1|]$ehتnd2 Uʔ$Bu_oS8{wI+ҬBmp2E&&8z(R@)C)mq h4xzMj2|~@ xp47^\C}No [jS (K HNf rrb˫M׉BMh5hh&BH&EN P !mA#s[Hz|(UL̂VNVz0}Ҳ( -@Yv7WDN;t8{@Şړ%B0!sRDQD`ޠVmE+B6/ +VjWxacc?qG255VUΝ;+m@fhxRLg(pd? =tF)~91=UJDX#]W "X&%U4&k[4Z֚C1w)R)9zp? T<)+;z{Y`y^:Q~xumKDAJT?|lFv䶫8#!!2k+k\psj{Md3,,Sk4B!" eXJoG~}UÍ-~ ([/|{y IN,=ozc2PS.iGu굆 IĘi%broXXs(+n.CdaZHtYbaa0WN({[Z.ߪY_ۤZk1S:o&SI] s,\E&GNvHf6de5V=6_8"`xgg ?J~٨6_')rCXNfkSI0i[(PB.K DQ R+*PK?cȖ] r5:ҕk Pٌ)F b>iԛٮ6w-aEj&D7ťB97`=jZ7gWt:z? @h|ᩗX]|c.[ g鶈MrwҺNhAF*H[)/XÍ?^rn굆 ȸi0 7D Z/Szԟ^\ewݳ*"KDQZqF^?L+l",o|\8K7^̛WHt.XXqS8 7 #N:&PʣPah4IkM U,$R(,m0.G0]vf%lhuת{x;]Q)iCޮ'sm#O2BV# +IGX vsWwkx/y3;z=K(2m+Bxڃ޶VV8f#L{wO=:f/ lw+8 !%ıe*t^_&Ƈ 4is7B8u4xnݙ4ڸ񞮙F`QBej[&aj?~c/r;<׿BB#L8B$tVMޡjv-X'[*b`tOz6HwCY:\gE-¦kIy4 {Ťa_}qdA$|wF'x!"Ko/s}aK$@jۨYVk#<ϸAzxxrL9REzEu_""#ٹ ^:7GV ࠕ3nF8ވi , Bqcy.d6ưᄯbey^[֢+ϡd8C ^%2$}6?D۽# &q !ltJʳ@ӲnOYvխ-זkCD~ĴZ 9޺JfP(`uRV 9"^w&~[(~&Zӱ!x+\[ K[[& /xQo?Q-=ۘkc;:4o]ZC*HFѤGX?fV $ָS<*bJa<֩Mtj'_f*`Ez  ?+{/nx)"ly7hv:aRc@ DuT`@X% kM H@a1(61CYki-O&E"FflfS\<)d2{78{M'T-J(U@PBt$j2&!k)$BCl#B:9+`VG)Dq[k+UT,(Nq`L.M IfzFȰlYm`RӠމh2W8L|~eϬG7ϩ;wey եUJL)?Kk#+hHWd-K90:N.o('f+|ܼi583H 0D{z)pQvd$":2 W*# t2Y/3 Y"~G\DfK63c.jt UjvFL@`;Լye*(fYg:nMJVIi:Ɛ7qs8ެw;g%-?#-}0wuSyq,|OQJRn1DJ11A*mpzȗ58r!Y0\]o/0?شG2a?xAKą,bv˗|mvpjr!l6?(ojdY f,y"(Fre;diYn"D\.Kvhf lCFdm7"X YjtBEB+ Y+hUMtWa3Ƈ_>Yo^_==9I#Ng'Z+KLM @[$3`rhcDrP^'?qJ]O[<2Q6PyD#{!3@+9oooꫯRFV dDvL,Aq qIV984=WuyR #9hk7-sh.Rm56V$g!N:7"AVcuXO'@ @sheVat [t (o8V6,q >p/7npbڃQlGw#Rkœ@Pou[dX dx`K$?<92F;l*E7jl\[\qryOc>7)";~{jE6۟R:j nRWBAA8T)\nG S5uN}eZQ TFill +pxxFbS.+./U]hmV\Zb5"ݫpVz߱ &dl-e\-3yl +>shFZnI+f1ðőӜ{"R!}swt }]w\_g/cDUNs)4RB E1cdD:gٮ0K&a O e VKݠ~H2RJVWWop3r8-S8)a%V6hFBqfrU4}{P_硓ӎXɁ^ zR!T?$By*!T!tcFb-'ki}e*s!u$|XfhR! N?đSСq UP`M`wf~[T{3lBoWXڲRmHB hjsj0!ak"VVVWF?'VO[xᇵz°5Q ˃cЄ`zN4D50X*`S@B==n^{]5'@*FGw{(Zs׼:0>uo|2. FlSy_ōjP{q'CeG) `|>Vs`XXෟ|f '@WHXh ( C6Нt{inYP' tRb73\O!0:y9ɂf`Ȣ<&ZHF0Xdx,jE#pѓB%[Dl=`zX0Q)0>1ő3=뜺~&[.ͱldzl8c8]7P[i;]*AFAѥL@R)u秲{NP)d)d\[\k/ m# ӗ-l\wn* _AS9+.RW1Z &E Nĵkר7lolDbɵgpxdʠfCR`qfd0ډu07#F ~:VfBm#:yf #_I;y\45Nabb<cBq7q,mՎ=_*P1x Uy IDATR2W6 ח(fJw:%4ϿՆӇG88RN]}@oVJ#҉_( 6שno$/$1[^kp,VG\_䇉͑yn*)wRS\+gyJS>8jͼzb:0>:L> 0?}fmZ㟥ʊX1j3\&ĉXkq}tz.287nXޢP)F> =Mk%dltks~Qi^4'>G>pߩ{g 2y&OT2n9byAdnGtzBf˜0Zgm}ul44D `XP(o0'Nrhe W<^IGo |wMVoJ!+˥K/Ԯ,7n ŭDgMc-szCͬ,lvzP[Rٖ-+-H $A 8_ $| P ZDF5fdlzw·Ϲ*ŮP:@XU{Y{_X2­YmXX27_B',cHF?Kb04ּc |7-cfAXzXk,xtݼ?mc4eUB# %ڻU].pՁf)-8B JX;}\5ƠVk9jRcRH/_<'חf-gn׿~q:ȳmum%*c)rճS8 7vG("/qK>ΰ!$AVf40AS)EU4{]Ξ^#*p{,wKlR݌ IbJ3)oM^ d8dցԃ n(;4Zms% aw܊5Hu&p32GbaBiQ0nGcZOfwx9(-{άNY8W˫1FZ+S€sO3_!qsQ*Rͭ>/}{y88k8wl0 rϝ ppK HpG[:( AL;GI%"3=l ŀ6Ng/{Ja 2xOw 4)ZNg%Q"[ ILj,k [ݘm,ֺ%ٻf<'z0\v@5  %g>/%wew=$IRʥ"I)FKq탃 0,/.P:BR1@X<Ϲ3YCNk\<)p@ko=|5y| Xm#SY2X6k$qpY5H$jz +7[, GE p./5V,T |>Đh5O@o|MIy/Ji

uSY[Yj2C.XW8ħ>Qnmmqsk:5'9kWx*sW quVnwB4\ncBۢfgBVb3yF4c~p!!z XBJgRXw?ocj:a%]a᫟$Mi{`S,.T\b`467 JJ(JC%wjL wlC?f3On^+SDq3X[82P.XP0W''摳'C#B.ndgFg4_s$[?e(s&|gX[YRkFF BSG/?iʑĦBZR/L~C_HBaԉ9YpyF2*hS\] l+%=IBX͈-!^Bs d A(h˵(uEmznLx;O,ac{y\HҊQaDBc2DaY>7 +ҹ4"1 S(1TGuN<}˾7>`̍&?|3f%B@P ,F:}òY+ H7i<~$ nbtc•j~̍֩ڑ ߌ/䝽iTڍJ55)c#ZJtc@7` $a<64Z@`dsX#_d.(`4v={s PM:Ղ`LX *i0t͞ShbJ R|M^z*{Mzf4q~Nˎ+y}7נ& !e&ayknd%W%N_l\$?}.eǸ 0-_{f,h7#Ry;F)~a!}yd0N#2Me;! FX7NA|$!;d;7™!H+[^LeY*$?ƚ[ #/a}eH`#܀PXssE*YQL)85+կno56OR*Nɞ b‰eVo޸2\HA"|}"OZ,F 4)P\6}oD D۔!ϴvHiw,l047tS2#mDڙJ:{O +cZ9= [;APsU w@%n pƎgA{3t?t{86^~[RxA5DA ]dPns,T}[M'gp_w!B?SXɵi&K435Fq:"'x(~eawN3T{ڐ{Z*txaDbU29S0BYK7RX V t8{dYaT0g>#4wJu<Ϙ F1q 3Y ^9ڰsO7݁a{aS-m8{ ?A͕hg-r:+G_/ϝ[!-*a<0ZRT@y`/_a9#K(Rc˿[ $Ȳ5HX\o@0h;dhO])Z8nkgEYPB| 3Ӹm,f'fo[& $ @J0n a2 F"$͔ՏfNϒ*N;Qts%ghcht$ƋP ~+Wy@Bd'K0ʉKRQ_x˻^u{/k)mi33bjS hSk#XGZ;_F?A^(wƴ`M*#<1ωZm•=F`9e#a  @=t?Om|9( 0R,)8hNvR@޳9h!2O \3RH16ɉ#! l7\aj:-ŀ67Ni$\B(g}u]J (1M03e T. `<"=N[ZfO|,Pƚ>Wr[ Dm #zOS.^O;R{ jp% lLڞ:mO2_,9e:՞8pvZ=UCR(HE޺[W8slr1@.)hp,X] 4+^I- hD@CX@ K 1ɃzjBD[֙yIVm${17AJ"[#֠p~W^2)sGc^^DP"|."dnf{C_,0Znl=FzK2I>h2S}{ZB'*1\K24MT c@)!aJ\"RANt7NSK7`1h_a;6ZΞj |s,84_W >Ha+9`'c@^]36I}Rtj82_ɳz&/}H%-d2.%84h`e3u^AɐdT%WE$ CC5(0,]:,)8IH;*DRNEdi%S Z'Xnl2rJ vu(ew=9dRmǞ.| h+k hj" : ^cubB/侷z ghrh lnﲴ8OTBI$M:>a\HLA<;iJK%v F+;)GbQ/|M1 絊[U}ݺl9'M0CJ0 hu;!VtG QPR Cj2i3cv<&Izm`SB9R L1ݯtt4~imΙL<+,IE(p.#h0\EꕂӭvbOgoތ: ?+I1pH $q i$HemIJIϕz /#t54:TEBvi~DL]X !Y IS37BwkHt(Q)o\H 1VmRT;q67\[.#ۣ, cDG0"5,fv@`_LBX`Ve4A|ll,<Ҳ@ ~#~׸S:V(K,3=g%$Z(~/ |\0> dkAi(CVjU€bP=x6wwkڝNL?=FTpzV t{GV帻%nlƔ7)V*&: ӕ:Rhn#3}!X [ zm'35(#*QHVx.6KKKJa|!U}Scgx|i& &W0v3K)7۱rq8C"O~#Hz(uuA\vVI_0r`h+~̋o$ _;5׃J#YO[lD?3Z]-푣JzNa*&:dD  *X][ z`# K%WSÄ͝ `?3l9ÃNVn넣K.d) 4aq@{0,רD[{{h3 l+302Ca^,`L0laPX]XfeFy Z˿3$kDZa~'#Z Mq!'(qK>xv ׁ:I?HA,` /p1"2s@1Mfis^á ^?ۯĘO5zNfb}Z7#xį~nNXk0\o)8ytzh٫5H\`YkNXcѠNbPD;F[d--`MJgH0Gx\KTd{!L0v zoh ng6D[8xkj:3"Gtzv-Օ2Woliv y\᯿stS?.sZ.2HPH+%?|tpZ 7i5oY FM1D0HjcZAVB^w'tCq8IyP ku$ڍһv(0ʉ=ן6 8bĂ 0B.yj25O,-֩TJ :>BRᤕojޭF'Su@2)i Wpwwm՞~|g0 =A$YR6XJSǏp6Hs :b _xykoqaILxw-~@7isHzdgO/߿ɛ X̨5- 0/ 'Cj}"TP IDAT6X_%cC;$J$3LCnº h73ˢuؗ/?qPR-#3_Msf1yJ jmZ #H^y 'n.k5]rVɘlB$߭5h? 9՛|bpL?b%fMĉ,sotYbЏi-*ޑi1}/XU6fc!0`n!oaJ\!ZsDQZB9XϺB xkMIXN_6m_)֌& +XDC\9k\֗'1% QأH敷6IRٟ|B!N2We nm g J(y2Oêfg !1ǩ#HpYҤܡ^O|E ^KY0)H HXZrƯN $F"X*=L%ԔE"EX" ubFHr}599!׶gJ{Po@8Glm=8-0fE Al7}?#!R٩ޭ!uf;͍Ftf诔B7xMZ?'XZ#`Me]-nD$EaZdܺ'tc.WF\`2-nQfiNӸ% msL6ѻbR2 ;. jWxFk-GT9;qd. $K5檨0DXqChgfl{8( /.>3%0‘Gw3}N8r᡽ր닌 բC;t 9}k7 G>eb@-G(77|w^gS<~nšlqBMߵg!c+DLH`7- Ce_-1icFl$23Q2,{7&~SH CңBZET0J5(j#Y2_/R(K(峷;HMpKe ֈ@:R(|+7-Y=$&竃S9߻̧.#IG4뿗 <6й~Z)GOP.x.^3;sgVBX+S‰] -X2OnZJUk9c njF1zVkњ81L R? n,\&TEzA1W A K!HkE*byN8KvDj!VP*%1f{WlϞ||#m|]{ǸPlG$ZEkރr:J0>y} GoI@ N,רW vyo|-.^/0_+_+Zm=#+/a~s`f{W_z ~TQe< ~c;6Gca鮿yNؘqJƱ'῔B,*ŧ/>_y'έS~}N)9yޠ+=)qE9S6s>/76 ʖ+y?|fMY"oXyvX"W>9RqP`Rzuea$02Zњx@ mڕ=4<;B5~/faTUAh1FGLto#a'+r,TjޥjV5X(-XC)W ߻Oȱջ{iArf.vʗX3įl?[6x!;mdJbғl>F,޾YָPƋE/w6SdY8bz=q0d{o@4WGY!"_Y.oόwL>Ib5IbGU3Jݔ]2Hk9qJƱ&$JY=Wnsu_o5~3qlNX)f:}g᭙)=f HvNϢ=Ȗ|Ę>L(3Vvj,nVA ?)RH1^``FIVuJT8lJ!q#S0ʱ"b2]C8)߻x7)k<#CVj5>&D"uUœ9ztKx6> \PA9Mp_<}KB@]Vu78g닿ϔ^!MSi[hdJo>d2%0V*gOsQ*/=1 g8Z݋6/lr{9wuf_%B{M9n9tJJ2Gt}z݄fC\˩Zs.VVzw[.cNkTRi!tFP*WY\^Fn'~DޯH> ukVW%Sɹ_Gȶuar(η(J ~S|ST ߼ɿ :CM>R~++3Buc &9uR a'I 'Rdo{q1G0?ipV?ʕZjYtWWf+AN8(CΝ9\NAOO=ʳP|땫7;Efsk~w7+61 arҪbiYidJ:azyYtĨǍmذs>\J~_đ>N>}ʹ!bǔerP{>S]ZzpfՖGX_scå ^|y䓧8rB큳r(pN0.+ƃ\N(Ħg3`S:ncY*Sݮhlm1n^ ˔f}SjKjo };pDE30׌5gk+,Wil2l@ʄ G+?@o0dsyKolK< 4 U@g!Q W>%7fl2]*y33S5`EЯ[MC'^^ ?+p>}摩V+e"bJ=q/d2zqnͽP,Ksȼ|`<\0M}e|;m{LqRk`NFKZ#NZ1=}How=|_۟|Jb|8TOLjJk~f'q) XƤ$Ƣdwa J֖Y[q|} ADI}1SOyeysQҢ݉yK\Gs3kQR)p: *_A~2??FPȑ(,,d"M6BYNUי]V^8+PF'[t{T~,gt2mllwզ7b[82Wa~.=\!|H%hmEs4;C˼vy i1FXh mگ׀s]at :O=#'א6XA}\Ⲏwyd1XL%Qyea;c{O)3' ƀ&ީ5 cnN2@a (㬮̱Teue@0BI~KwJ+hfF;)r &2Bi7& րF^A ,Q, Lj2K$mhG$^8v{?Fdl@ 7; fŨxR}D3 nC&_݊h\z3zZFegg4qH^R׺ ݿUR.NS@NX3H,/q@RU ֖8z:@6) /3" (cш0XF185$q.>F\ظorkA!I%kݻ\κCh~P2׃tḙFaN1$ rO|(%N谿 N@zml0^Nz)%PJsȂ_.#PZXc0Zc>m{-vm0-;ΌNfN8_zXHj, X}u}qycFAT!;j|ya'|2f8ȓe=} *|3#Tj,8hoDDZ2379If*@)0X39~ g=F5}j^|G M$:-c1Rɘ;CTB<JE:xN:MB.#b#,{ˏv1I&γbV1Sξ{B(9`>) }? ,"FkXc 3\P,=KT ~q|A%5djp)eۉ?(*c5KIZP<5Y{M8q\铜>ub)D+$t8&3s#*`fZ%hۤi ಿ(BFpvf bsvg_8{t=4SҗNg笔q2rA\~Bf{ -%T*92… -.Q( EsVRM2PܹCy%MҏVVx8U>\*ww$RaaJZ?t:=FT## ަTE_XJg]jt,=' @Mi;ZR^*e1qTnKP*3 ެ7~p1WX u $a˾-9 a=8̫;S8.DQr*NZ4&c%~^.n+w=|-fūF阱v©BJB曌:~iqh Zj?)&h'[Oݕe58?ǧz{CbiqqRtW8B'|B2E{`1& X2M J(""6|qRd _oO-p+cj s|e9*H3S,"B&0GjqO<"'GIT/FtRv۸+z0pmПVF^ 6>hKpȴ1@RDpZ  ktWuΞ=S6Ibm{am=[YjD! -38pz}NeVD{W/,,y {LN[vv+ N~6w;H)&p| &[f듉<Ob5  7[\؛>! ̏R? /P.Q|wB>,sO> ?rf m .oN4ˏuO tVJ9IWJ%M% !Sԧ~#֖cs{C6L> w+ǙX~?G!fJ$܄-+<[R㏳|$e;i)~9Wx70qk%5& xbxǽ{.} +yP(O8f]tRؙJȀk nLC!a=%3Wj ޻Vp3Z^26 ,py9䃸ns{3%^ọ,;SnYW|PӉuHf `ȅ%W[Ǯ 'rkL?0fdiY8>h-(FD2R+ZofmDxg;r 1~@ Ns\%cU\U=*%r<6㧨x#QRZRKEY |$ۯʼxy W|t߱?zT3hexQ7R6L:3tSl+S2?)B5%\` 4kL3Ȁ@x^S"}hbnY;vv+0@ƪA9mjj`mމ'2!T>o,rޥB%mZ&p 5^AuWbՓIcc#7ֻH Wgw?J`vD>2e|ٚ|G$3 !PJdHJ:Ȭd4_Z #܏O7}81J[-mJ% `AK|>ϸqȢjj֕7&7LM-\d"8|]Mn)A}\QV"#]U3#2rWNLgon o$$^xڗ/984P-xO2p)5RYk RF,b#'AE5>mJ)RM{"pߓ=ɺgyDZJ%7<;RF FCޗҵ A@=E9xO.Fw<\RGMBȅ2D,eg'J-,a෸^d"c鍴ϪJt9 8`M*.Ӿ~4j 6m}'UPW[>7|N/ϒamJ4z@؏$.6WBg)`]8F}U%ê udT- 7`!iN 1GH{| t5ЉZXmܻ~5v!0dD&Xb9x|'gjd>V\aSz^X͜s/eK L= FȰ|eCӇ5@m'pHIXOr>K^j7B͔5H\U"/:;_o}+1l4dn5+)ꭩ7m>P+nwg Q yB%|̯H<\.ƕjZB)k:[fqġޥ@aǵ4&nc!߻VJFT&t a)fvpڥ~?01\@'߅ x=/մrȉa qzYWӡ~pT`65ֽ^)1=4:]ツTS Y&0شu߼V}ޫvC(ҕKrqHq;a0•`:y#L?(P|q $1"o \c"zU,["R+#=1#jgD2)mdbim}[AtJ:ێH<}+/E.E%FX !k%֊cX{a<}f yqLm"aYPKos.tq:W`|Y3&$~t n^qF"m|0\P@-N{&,@"\_Ejrŏƺz⨜nI~sQu3$ Nƈ3Z4CV}8\w$@ֱŵώ6_b,()F#ܸW)!+S'xf %z:favl>S[ns'|4n[@oh(1lݺ?<RJ5o'ǻ˂[ $ u<*S7s.es+ =&OS$@*.]A!35dY&O:MM mfKN #x,!)|XooVy 7M!,IfrE n{V6oBSS=͓8Ӛhq]reyoǜUn⺢擪+[p§Ogي x | }aƖM$4"UW/^]wMgGW IFh˟YNX5==9'Ml6gV4(\)@1 g*lmmcyrG1VE)`>)Tc{QGѺ !*BҧxUtt\M㏜NcC8/K[NgI\u79zt@"uPdbٌ䀱JeZZ[Yq0OV)Ҳ- $L_j̻ߨPǕ/70Dύ.<;zx`S9c:ȋ`A =uAڕ5ɹjk9w0퐃ںaA](K 4 3fEc\: k93އۋ9Ν,(F/˥&>eg3CZs^QC(o3N+ZƍY5ƍ1y"-7PCUe +Ɍ˟!IL=āģ xpaRENhsN?}qH!TB~FMo@ ijE TxǿH 8iW_':$@FIwɿe8~}ޝUmҽ}U` nYa؏| ~j3vD6G8_+ JI=>,+6TۼɿEsbiT+JK'ekgxkL#D606P_'GY),`J~E`KTkH*YJ:-)YkvcS4g hdKK%lltWu;o%ezB,*n8(c=1(aor5[)LJ-GqM"\~ m|f]wgMLm"~5^3L'RIbI N`Gq)p"\ ^}ŒZFe0XpU#hJye堃&[&0MJ6hE_8֬GP Yt|]k xrrRVũāoW?Iއ19^S+V'XƺոȤZbJ&4~l $|ͭ2~ut1k#w?V'ŝJ,LpФTf@H38H+. ʆLHO~S+ ,EX }ɏYvSP,[N~0H 711 8r ׯl+g_=M$#f$[E@@ h.9@GWKA )q(w?iH9wjK5ϩ#ֽ^_ϼYOmt?#X@}G @u`)Ts[[;˞[EB}W e q@u`p듁K5;օgUH1). q@" v|产9 ?a!h'M5\8 8|9\ˮFG׍ $$A"]K^x !kV CϏ+'Tm +go_|׿S rA,!H0hO1lmK ^kt.Fkp}k6mxy>AjFu&!hylq̑3a`r|{n 4jwx $} 8i8$m7_$5Ý/`$d~HW})p@ }jpJ0NAI8PDIENDB`leiningen-2.9.1/resources/leiningen/000077500000000000000000000000001343535564500174725ustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/bootclasspath-deps.clj000066400000000000000000000053251343535564500237700ustar00rootroot00000000000000;; This file is used to warn users when they attempt to load a plugin that ;; pulls in a dependency which conflicts with something already in use ;; by Leiningen itself. ;; This code regenerates the map #_(do (require '[leiningen.core.project :as project]) (require '[leiningen.core.classpath :as cp]) (require '[clojure.pprint :as pp]) (defn artifacts [h] (apply concat (keys h) (map artifacts (vals h)))) (let [hierarchy (cp/managed-dependency-hierarchy :dependencies :managed-dependencies (project/read))] (-> (into {} (for [[a v] (artifacts hierarchy)] [a v])) ;; Unhelpful to warn on these: (dissoc 'org.clojure/clojure) (dissoc 'leiningen-core) (pp/pprint)))) { clojure-complete "0.2.5" com.cemerick/pomegranate "1.1.0" com.google.guava/guava "20.0" com.hypirion/io "0.3.1" commons-codec "1.9" commons-io "2.6" commons-lang "2.6" commons-logging "1.2" javax.inject "1" net.cgrand/parsley "0.9.3" net.cgrand/regex "1.1.0" net.cgrand/sjacket "0.1.1" nrepl "0.6.0" org.apache.commons/commons-lang3 "3.5" org.apache.httpcomponents/httpclient "4.5.3" org.apache.httpcomponents/httpcore "4.4.6" org.apache.maven.resolver/maven-resolver-api "1.1.1" org.apache.maven.resolver/maven-resolver-connector-basic "1.0.3" org.apache.maven.resolver/maven-resolver-impl "1.1.1" org.apache.maven.resolver/maven-resolver-spi "1.1.1" org.apache.maven.resolver/maven-resolver-transport-file "1.0.3" org.apache.maven.resolver/maven-resolver-transport-http "1.0.3" org.apache.maven.resolver/maven-resolver-transport-wagon "1.0.3" org.apache.maven.resolver/maven-resolver-util "1.1.1" org.apache.maven.wagon/wagon-http "3.0.0" org.apache.maven.wagon/wagon-http-shared "3.0.0" org.apache.maven.wagon/wagon-provider-api "3.0.0" org.apache.maven/maven-artifact "3.5.3" org.apache.maven/maven-builder-support "3.5.3" org.apache.maven/maven-model "3.5.3" org.apache.maven/maven-model-builder "3.5.3" org.apache.maven/maven-repository-metadata "3.5.3" org.apache.maven/maven-resolver-provider "3.5.3" org.clojure/core.specs.alpha "0.2.44" org.clojure/data.xml "0.0.8" org.clojure/spec.alpha "0.2.176" org.clojure/tools.macro "0.1.5" org.codehaus.plexus/plexus-component-annotations "1.7.1" org.codehaus.plexus/plexus-interpolation "1.24" org.codehaus.plexus/plexus-utils "3.1.0" org.flatland/classlojure "0.7.1" org.jsoup/jsoup "1.7.2" org.slf4j/slf4j-api "1.7.25" org.slf4j/slf4j-nop "1.7.25" org.tcrawley/dynapath "1.0.0" quoin "0.1.2" robert/hooke "1.3.0" scout "0.1.1" stencil "0.5.0" timofreiberg/bultitude "0.3.0" } leiningen-2.9.1/resources/leiningen/help/000077500000000000000000000000001343535564500204225ustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/copying000077700000000000000000000000001343535564500237042../../../COPYINGustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/deploying000077700000000000000000000000001343535564500252562../../../doc/DEPLOY.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/faq000077700000000000000000000000001343535564500234462../../../doc/FAQ.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/gpg000077700000000000000000000000001343535564500234622../../../doc/GPG.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/mixed-source000077700000000000000000000000001343535564500270532../../../doc/MIXED_PROJECTS.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/news000077700000000000000000000000001343535564500232532../../../NEWS.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/profiles000077700000000000000000000000001343535564500253362../../../doc/PROFILES.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/project.clj000077700000000000000000000000001343535564500270362../../../sample.project.cljustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/readme000077700000000000000000000000001343535564500237152../../../README.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/sample000077700000000000000000000000001343535564500261022../../../sample.project.cljustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/templates000077700000000000000000000000001343535564500256242../../../doc/TEMPLATES.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/help/tutorial000077700000000000000000000000001343535564500253762../../../doc/TUTORIAL.mdustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/new/000077500000000000000000000000001343535564500202635ustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/new/app/000077500000000000000000000000001343535564500210435ustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/new/app/CHANGELOG.md000066400000000000000000000013761343535564500226630ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). ## [Unreleased] ### Changed - Add a new arity to `make-widget-async` to provide a different widget shape. ## [0.1.1] - {{date}} ### Changed - Documentation on how to make the widgets. ### Removed - `make-widget-sync` - we're all async, all the time. ### Fixed - Fixed widget maker to keep working when daylight savings switches over. ## 0.1.0 - {{date}} ### Added - Files from the new template. - Widget maker public API - `make-widget-sync`. [Unreleased]: https://github.com/your-name/{{name}}/compare/0.1.1...HEAD [0.1.1]: https://github.com/your-name/{{name}}/compare/0.1.0...0.1.1 leiningen-2.9.1/resources/leiningen/new/app/LICENSE000066400000000000000000000335661343535564500220650ustar00rootroot00000000000000Eclipse Public License - v 2.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 content 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 changes or additions to the Program that are not Modified Works. "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 or any Secondary License (as applicable), including Contributors. "Derivative Works" shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. "Modified Works" shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. "Distribute" means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. "Source Code" means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. "Secondary License" means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. 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. 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 or other 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. e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). 3. REQUIREMENTS 3.1 If a Contributor Distributes the Program in any form, then: a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: i) effectively disclaims on behalf of all other 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 other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. 3.2 When the Program is Distributed as Source Code: a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and b) a copy of this Agreement must be included with each copy of the Program. 3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability ("notices") contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. 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, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, 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, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, 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. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. Exhibit A - Form of Secondary Licenses Notice "This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}." Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership.leiningen-2.9.1/resources/leiningen/new/app/README.md000066400000000000000000000017271343535564500223310ustar00rootroot00000000000000# {{name}} FIXME: description ## Installation Download from http://example.com/FIXME. ## Usage FIXME: explanation $ java -jar {{name}}-0.1.0-standalone.jar [args] ## Options FIXME: listing of options this app accepts. ## Examples ... ### Bugs ... ### Any Other Sections ### That You Think ### Might be Useful ## License Copyright © {{year}} FIXME This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html. leiningen-2.9.1/resources/leiningen/new/app/core.clj000066400000000000000000000001731343535564500224660ustar00rootroot00000000000000(ns {{namespace}} (:gen-class)) (defn -main "I don't do a whole lot ... yet." [& args] (println "Hello, World!")) leiningen-2.9.1/resources/leiningen/new/app/gitignore000066400000000000000000000001571343535564500227600ustar00rootroot00000000000000/target /classes /checkouts profiles.clj pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port .hgignore .hg/leiningen-2.9.1/resources/leiningen/new/app/hgignore000066400000000000000000000002251343535564500225670ustar00rootroot00000000000000syntax: glob pom.xml pom.xml.asc *.jar *.class .gitignore .git/** syntax: regexp ^.nrepl-port ^.lein-.* ^target/ ^classes/ ^checkouts/ profiles.clj leiningen-2.9.1/resources/leiningen/new/app/intro.md000066400000000000000000000001521343535564500225160ustar00rootroot00000000000000# Introduction to {{name}} TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) leiningen-2.9.1/resources/leiningen/new/app/project.clj000066400000000000000000000006171343535564500232070ustar00rootroot00000000000000(defproject {{raw-name}} "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" :url "https://www.eclipse.org/legal/epl-2.0/"} :dependencies [[org.clojure/clojure "1.10.0"]] :main ^:skip-aot {{namespace}} :target-path "target/%s" :profiles {:uberjar {:aot :all}}) leiningen-2.9.1/resources/leiningen/new/app/test.clj000066400000000000000000000002501343535564500225110ustar00rootroot00000000000000(ns {{namespace}}-test (:require [clojure.test :refer :all] [{{namespace}} :refer :all])) (deftest a-test (testing "FIXME, I fail." (is (= 0 1)))) leiningen-2.9.1/resources/leiningen/new/default/000077500000000000000000000000001343535564500217075ustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/new/default/CHANGELOG.md000066400000000000000000000013761343535564500235270ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). ## [Unreleased] ### Changed - Add a new arity to `make-widget-async` to provide a different widget shape. ## [0.1.1] - {{date}} ### Changed - Documentation on how to make the widgets. ### Removed - `make-widget-sync` - we're all async, all the time. ### Fixed - Fixed widget maker to keep working when daylight savings switches over. ## 0.1.0 - {{date}} ### Added - Files from the new template. - Widget maker public API - `make-widget-sync`. [Unreleased]: https://github.com/your-name/{{name}}/compare/0.1.1...HEAD [0.1.1]: https://github.com/your-name/{{name}}/compare/0.1.0...0.1.1 leiningen-2.9.1/resources/leiningen/new/default/LICENSE000066400000000000000000000335661343535564500227310ustar00rootroot00000000000000Eclipse Public License - v 2.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 content 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 changes or additions to the Program that are not Modified Works. "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 or any Secondary License (as applicable), including Contributors. "Derivative Works" shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. "Modified Works" shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. "Distribute" means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. "Source Code" means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. "Secondary License" means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. 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. 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 or other 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. e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). 3. REQUIREMENTS 3.1 If a Contributor Distributes the Program in any form, then: a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: i) effectively disclaims on behalf of all other 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 other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. 3.2 When the Program is Distributed as Source Code: a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and b) a copy of this Agreement must be included with each copy of the Program. 3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability ("notices") contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. 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, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, 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, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, 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. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. Exhibit A - Form of Secondary Licenses Notice "This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}." Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership.leiningen-2.9.1/resources/leiningen/new/default/README.md000066400000000000000000000013561343535564500231730ustar00rootroot00000000000000# {{name}} A Clojure library designed to ... well, that part is up to you. ## Usage FIXME ## License Copyright © {{year}} FIXME This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html. leiningen-2.9.1/resources/leiningen/new/default/core.clj000066400000000000000000000001371343535564500233320ustar00rootroot00000000000000(ns {{namespace}}) (defn foo "I don't do a whole lot." [x] (println x "Hello, World!")) leiningen-2.9.1/resources/leiningen/new/default/gitignore000066400000000000000000000001571343535564500236240ustar00rootroot00000000000000/target /classes /checkouts profiles.clj pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port .hgignore .hg/leiningen-2.9.1/resources/leiningen/new/default/hgignore000066400000000000000000000002061343535564500234320ustar00rootroot00000000000000syntax: glob target/** classes/** checkouts/** profiles.clj pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port .gitignore .git/**leiningen-2.9.1/resources/leiningen/new/default/intro.md000066400000000000000000000001521343535564500233620ustar00rootroot00000000000000# Introduction to {{name}} TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) leiningen-2.9.1/resources/leiningen/new/default/project.clj000066400000000000000000000005311343535564500240460ustar00rootroot00000000000000(defproject {{raw-name}} "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" :url "https://www.eclipse.org/legal/epl-2.0/"} :dependencies [[org.clojure/clojure "1.10.0"]] :repl-options {:init-ns {{namespace}}}) leiningen-2.9.1/resources/leiningen/new/default/test.clj000066400000000000000000000002501343535564500233550ustar00rootroot00000000000000(ns {{namespace}}-test (:require [clojure.test :refer :all] [{{namespace}} :refer :all])) (deftest a-test (testing "FIXME, I fail." (is (= 0 1)))) leiningen-2.9.1/resources/leiningen/new/plugin/000077500000000000000000000000001343535564500215615ustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/new/plugin/CHANGELOG.md000066400000000000000000000013761343535564500234010ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). ## [Unreleased] ### Changed - Add a new arity to `make-widget-async` to provide a different widget shape. ## [0.1.1] - {{date}} ### Changed - Documentation on how to make the widgets. ### Removed - `make-widget-sync` - we're all async, all the time. ### Fixed - Fixed widget maker to keep working when daylight savings switches over. ## 0.1.0 - {{date}} ### Added - Files from the new template. - Widget maker public API - `make-widget-sync`. [Unreleased]: https://github.com/your-name/{{name}}/compare/0.1.1...HEAD [0.1.1]: https://github.com/your-name/{{name}}/compare/0.1.0...0.1.1 leiningen-2.9.1/resources/leiningen/new/plugin/LICENSE000066400000000000000000000335661343535564500226030ustar00rootroot00000000000000Eclipse Public License - v 2.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 content 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 changes or additions to the Program that are not Modified Works. "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 or any Secondary License (as applicable), including Contributors. "Derivative Works" shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. "Modified Works" shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. "Distribute" means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. "Source Code" means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. "Secondary License" means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. 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. 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 or other 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. e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). 3. REQUIREMENTS 3.1 If a Contributor Distributes the Program in any form, then: a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: i) effectively disclaims on behalf of all other 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 other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. 3.2 When the Program is Distributed as Source Code: a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and b) a copy of this Agreement must be included with each copy of the Program. 3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability ("notices") contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. 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, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, 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, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, 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. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. Exhibit A - Form of Secondary Licenses Notice "This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}." Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership.leiningen-2.9.1/resources/leiningen/new/plugin/README.md000066400000000000000000000020621343535564500230400ustar00rootroot00000000000000# {{name}} A Leiningen plugin to do many wonderful things. ## Usage FIXME: Use this for user-level plugins: Put `[{{name}} "0.1.0-SNAPSHOT"]` into the `:plugins` vector of your `:user` profile. FIXME: Use this for project-level plugins: Put `[{{name}} "0.1.0-SNAPSHOT"]` into the `:plugins` vector of your project.clj. FIXME: and add an example usage that actually makes sense: $ lein {{unprefixed-name}} ## License Copyright © {{year}} FIXME This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html. leiningen-2.9.1/resources/leiningen/new/plugin/gitignore000066400000000000000000000001571343535564500234760ustar00rootroot00000000000000/target /classes /checkouts profiles.clj pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port .hgignore .hg/leiningen-2.9.1/resources/leiningen/new/plugin/hgignore000066400000000000000000000002061343535564500233040ustar00rootroot00000000000000syntax: glob target/** classes/** checkouts/** profiles.clj pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port .gitignore .git/**leiningen-2.9.1/resources/leiningen/new/plugin/name.clj000066400000000000000000000001721343535564500231730ustar00rootroot00000000000000(ns leiningen.{{unprefixed-name}}) (defn {{unprefixed-name}} "I don't do a lot." [project & args] (println "Hi!")) leiningen-2.9.1/resources/leiningen/new/plugin/project.clj000066400000000000000000000004251343535564500237220ustar00rootroot00000000000000(defproject {{name}} "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" :url "https://www.eclipse.org/legal/epl-2.0/"} :eval-in-leiningen true) leiningen-2.9.1/resources/leiningen/new/template/000077500000000000000000000000001343535564500220765ustar00rootroot00000000000000leiningen-2.9.1/resources/leiningen/new/template/CHANGELOG.md000066400000000000000000000013761343535564500237160ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). ## [Unreleased] ### Changed - Add a new arity to `make-widget-async` to provide a different widget shape. ## [0.1.1] - {{date}} ### Changed - Documentation on how to make the widgets. ### Removed - `make-widget-sync` - we're all async, all the time. ### Fixed - Fixed widget maker to keep working when daylight savings switches over. ## 0.1.0 - {{date}} ### Added - Files from the new template. - Widget maker public API - `make-widget-sync`. [Unreleased]: https://github.com/your-name/{{name}}/compare/0.1.1...HEAD [0.1.1]: https://github.com/your-name/{{name}}/compare/0.1.0...0.1.1 leiningen-2.9.1/resources/leiningen/new/template/LICENSE000066400000000000000000000335661343535564500231200ustar00rootroot00000000000000Eclipse Public License - v 2.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 content 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 changes or additions to the Program that are not Modified Works. "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 or any Secondary License (as applicable), including Contributors. "Derivative Works" shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. "Modified Works" shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. "Distribute" means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. "Source Code" means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. "Secondary License" means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. 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. 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 or other 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. e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). 3. REQUIREMENTS 3.1 If a Contributor Distributes the Program in any form, then: a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: i) effectively disclaims on behalf of all other 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 other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. 3.2 When the Program is Distributed as Source Code: a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and b) a copy of this Agreement must be included with each copy of the Program. 3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability ("notices") contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. 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, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, 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, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, 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. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. Exhibit A - Form of Secondary Licenses Notice "This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}." Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership.leiningen-2.9.1/resources/leiningen/new/template/README.md000066400000000000000000000013161343535564500233560ustar00rootroot00000000000000# {{name}} A Leiningen template for FIXME. ## Usage FIXME ## License Copyright © {{year}} FIXME This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0. This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html. leiningen-2.9.1/resources/leiningen/new/template/foo.clj000066400000000000000000000000241343535564500233470ustar00rootroot00000000000000(def {{name}} :foo) leiningen-2.9.1/resources/leiningen/new/template/gitignore000066400000000000000000000001421343535564500240050ustar00rootroot00000000000000/target /classes /checkouts pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port .hgignore .hg/leiningen-2.9.1/resources/leiningen/new/template/hgignore000066400000000000000000000002061343535564500236210ustar00rootroot00000000000000syntax: glob target/** classes/** checkouts/** profiles.clj pom.xml pom.xml.asc *.jar *.class /.lein-* /.nrepl-port .gitignore .git/**leiningen-2.9.1/resources/leiningen/new/template/project.clj000066400000000000000000000004431343535564500242370ustar00rootroot00000000000000(defproject {{name}}/lein-template "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" :url "https://www.eclipse.org/legal/epl-2.0/"} :eval-in-leiningen true) leiningen-2.9.1/resources/leiningen/new/template/temp.clj000066400000000000000000000007231343535564500235370ustar00rootroot00000000000000(ns leiningen.new.{{name}} (:require [leiningen.new.templates :refer [renderer name-to-path ->files]] [leiningen.core.main :as main])) (def render (renderer "{{name}}")) (defn {{name}} "FIXME: write documentation" [name] (let [data {:name name :sanitized (name-to-path name)}] (main/info "Generating fresh 'lein new' {{name}} project.") (->files data ["src/{{placeholder}}/foo.clj" (render "foo.clj" data)]))) leiningen-2.9.1/resources/repl-welcome000066400000000000000000000004001343535564500200320ustar00rootroot00000000000000 Docs: (doc function-name-here) (find-doc "part-of-name-here") Source: (source function-name-here) Javadoc: (javadoc java-object-or-class-here) Exit: Control+D or (exit) or (quit) Results: Stored in vars *1, *2, *3, an exception in *e leiningen-2.9.1/sample.project.clj000066400000000000000000000737041343535564500171430ustar00rootroot00000000000000;; This is an annotated reference of the options that may be set in a ;; project.clj file. It is fairly contrived in order to cover lots of ;; different options; it shouldn't be considered a representative ;; configuration. For a more detailed explanation of some of the terms ;; run `lein help tutorial`. ;; These options apply to Leiningen 2.x. See the 1.x branch for older versions: ;; https://github.com/technomancy/leiningen/blob/1.x/sample.project.clj ;; The project is named "sample", and its group-id is "org.example". (defproject org.example/sample "1.0.0-SNAPSHOT" ; version "1.0.0-SNAPSHOT" ;; Beyond this point you may prepend a form with unquote, or ~, to eval it. ;;; Project Metadata ;; The description text is searchable from repositories like Clojars. :description "A sample project" :url "http://example.org/sample-clojure-project" ;; The mailing list of the project. If the project has multiple mailing ;; lists, use the :mailing-lists key (bound to a seq of mailing list ;; descriptions as below). :mailing-list {:name "sample mailing list" :archive "http://example.org/sample-mailing-list-archives" :other-archives ["http://example.org/sample-list-archive2" "http://example.org/sample-list-archive3"] :post "list@example.org" :subscribe "list-subscribe@example.org" :unsubscribe "list-unsubscribe@example.org"} ;; The project's license. :distribution should be :repo or :manual; ;; :repo means it is OK for public repositories to host this project's ;; artifacts. A seq of :licenses is also supported. :license {:name "Eclipse Public License - v 1.0" :url "http://www.eclipse.org/legal/epl-v10.html" :distribution :repo :comments "same as Clojure"} ;; Warns users of earlier versions of Leiningen. Set this if your project ;; relies on features only found in newer Leiningen versions. :min-lein-version "2.0.0" ;; You can require a specific version of Leiningen. In case of mismatch ;; execution will abort. When versions are compared, suffixes such as ;; "-SNAPSHOT" are dropped. ;; :exact-lein-version "2.8.2" ;;; Dependencies, Plugins, and Repositories ;; Dependencies are listed as [group-id/name version]; in addition ;; to keywords supported by Pomegranate, you can use :native-prefix ;; to specify a prefix. This prefix is used to extract natives in ;; jars that don't adhere to the default "//" layout that ;; Leiningen expects. ;; You can also strings like ["group-id/name" version] for instances ;; where the dependency name isn't a valid symbol literal. :dependencies [[org.clojure/clojure "1.3.0"] [org.jclouds/jclouds "1.0" :classifier "jdk15"] [net.sf.ehcache/ehcache "2.3.1" :extension "pom"] [log4j "1.2.15" :exclusions [[javax.mail/mail :extension "jar"] [javax.jms/jms :classifier "*"] com.sun.jdmk/jmxtools com.sun.jmx/jmxri]] ["net.3scale/3scale-api" "3.0.2"] [org.lwjgl.lwjgl/lwjgl "2.8.5"] [org.lwjgl.lwjgl/lwjgl-platform "2.8.5" :classifier "natives-osx" ;; LWJGL stores natives in the root of the jar; this ;; :native-prefix will extract them. :native-prefix ""]] ;; "Managed Dependencies" are a concept borrowed from maven pom files; see ;; https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management ;; Managed dependencies allow you to specify a desired version number for a dependency ;; *if* the dependency exists (often transitively), but a managed dependency ;; will not actually cause the described artifact to be a dependency on its own. ;; This feature is most useful in combination with some other mechanism for ;; defining a "parent project"; e.g. you can have a "parent project" that specifies ;; managed dependencies for common libraries that you use frequently in your other ;; projects, and then the downstream/child projects can specify a normal dependency on ;; those libraries *without specifying a version number*, and thus will inherit ;; the version number from the parent. This provides a simpler means of keeping ;; common dependency versions in sync across a large number of clojure libraries. ;; For more info see ./doc/MANAGED_DEPS.md and https://github.com/achin/lein-parent :managed-dependencies [[clj-time "0.12.0"] [me.raynes/fs "1.4.6"]] ;; What to do in the case of version conflicts. Defaults to :ranges, which ;; warns when version ranges are present anywhere in the dependency tree, ;; but can be set to true to warn for both ranges and overrides, or :abort ;; to exit in the case of ranges or overrides. Setting this to :warn or ;; :abort will also warn you when plugins or their dependencies ;; conflict with libraries used by Leiningen itself. :pedantic? :abort ;; Global exclusions are applied across the board, as an alternative ;; to duplication for multiple dependencies with the same excluded libraries. :exclusions [org.apache.poi/poi org.apache.poi/poi-ooxml] ;; Plugins are code that runs in Leiningen itself and usually ;; provide new tasks or hooks. :plugins [[lein-pprint "1.1.1"] [lein-assoc "0.1.0"] [s3-wagon-private "1.1.1"] [lein-foo "0.0.1" :hooks false] [lein-bar "0.0.1" :middleware false]] ;; These repositories will be searched for :dependencies and ;; :plugins and will also be available to deploy to. ;; Add ^:replace (:repositories ^:replace [...]) to only use repositories you ;; list below. :repositories [["java.net" "https://download.java.net/maven/2"] ["sonatype" {:url "https://oss.sonatype.org/content/repositories/releases" ;; If a repository contains releases only setting ;; :snapshots to false will speed up dependencies. :snapshots false ;; Disable signing releases deployed to this repo. ;; (Not recommended.) :sign-releases false ;; You can also set the policies for how to handle ;; :checksum failures to :fail, :warn, or :ignore. :checksum :fail ;; How often should this repository be checked for ;; snapshot updates? (:daily, :always, or :never) :update :always ;; You can also apply them to releases only: :releases {:checksum :fail :update :always}}] ;; Repositories named "snapshots" and "releases" automatically ;; have their :snapshots and :releases disabled as appropriate. ;; Credentials for repositories should *not* be stored ;; in project.clj but in ~/.lein/credentials.clj.gpg instead, ;; see `lein help deploying` under "Authentication". ["snapshots" "https://blueant.com/archiva/snapshots"] ["releases" {:url "https://blueant.com/archiva/internal" ;; Using :env as a value here will cause an ;; environment variable to be used based on ;; the key; in this case LEIN_PASSWORD. :username "milgrim" :password :env}]] ;; These repositories will be included with :repositories when loading plugins. ;; This would normally be set in a profile for non-public repositories. ;; All the options are the same as in the :repositories map. :plugin-repositories [["internal-plugin-repo" "http://example.org/repo"]] ;; Fetch dependencies from mirrors. Mirrors override repositories when the key ;; in the :mirrors map matches either the name or URL of a specified ;; repository. All settings supported in :repositories may be set here too. ;; The :name should match the name of the mirrored repository. :mirrors {"central" {:name "central" :url "http://mirrors.ibiblio.org/pub/mirrors/maven2"} #"clojars" {:name "Internal nexus" :url "http://mvn.local/nexus/releases" :repo-manager true}} ;; Override location of the local maven repository. Relative to project root. :local-repo "local-m2" ;; You can set :update and :checksum policies here to have them ;; apply for all :repositories. Usually you will not set :update ;; directly but apply the "update" profile instead. :update :always :checksum :fail ;; Prevent Leiningen from checking the network for dependencies. ;; This wouldn't normally be set in project.clj; it would come from a profile. :offline? true ;; the deploy task will give preference to repositories specified in ;; :deploy-repositories, and repos listed there will not be used for ;; dependency resolution. :deploy-repositories [["releases" {:url "http://blueant.com/archiva/internal/releases" ;; Select a GPG private key to use for ;; signing. (See "How to specify a user ;; ID" in GPG's manual.) GPG will ;; otherwise pick the first private key ;; it finds in your keyring. ;; Currently only works in :deploy-repositories ;; or as a top-level (global) setting. :signing {:gpg-key "0xAB123456"}}] ["snapshots" "http://blueant.com/archiva/internal/snapshots"]] ;; Defaults for signing options. Defers to per-repository settings. :signing {:gpg-key "root@eruditorum.org"} ;; If you configure a custom repository with a self-signed SSL ;; certificate, you will need to add it here. Paths should either ;; be on Leiningen's classpath or relative to the project root. :certificates ["blueant.pem"] ;;; Profiles ;; Each active profile gets merged into the project map. The :dev ;; and :user profiles are active by default, but the latter should be ;; looked up in ~/.lein/profiles.clj rather than set in project.clj. ;; Use the with-profiles higher-order task to run a task with a ;; different set of active profiles. ;; See `lein help profiles` for a detailed explanation. :profiles {:debug {:debug true :injections [(prn (into {} (System/getProperties)))]} :1.4 {:dependencies [[org.clojure/clojure "1.4.0"]]} :1.5 {:dependencies [[org.clojure/clojure "1.5.0"]]} ;; activated by default :dev {:resource-paths ["dummy-data"] :dependencies [[clj-stacktrace "0.2.4"]]} ;; activated automatically during uberjar :uberjar {:aot :all} ;; activated automatically in repl task :repl {:plugins [[cider/cider-nrepl "0.7.1"]]}} ;; Load these namespaces from within Leiningen to pick up hooks from them. :hooks [leiningen.hooks.difftest] ;; Apply these middleware functions from plugins to your project ;; when it loads. Both hooks and middleware can be loaded implicitly ;; or by being listed here. :middleware [lein-xml.plugin/middleware] ;; These settings disable the implicit loading of middleware and ;; hooks, respectively. You can disable both with :implicits false. :implicit-middleware false :implicit-hooks false ;;; Entry Point ;; The -main function in this namespace will be run at launch ;; (either via `lein run` or from an uberjar). It should be variadic: ;; ;; (ns my.service.runner ;; (:gen-class)) ;; ;; (defn -main ;; "Application entry point" ;; [& args] ;; (comment Do app initialization here)) ;; ;; This will be AOT compiled by default; to disable this, attach ^:skip-aot ;; metadata to the namespace symbol. ^:skip-aot will not disable AOT ;; compilation of :main when :aot is :all or contains the main class. It's ;; best to be explicit with the :aot key rather than relying on ;; auto-compilation of :main. Setting :main to nil is useful when a ;; project contains several main functions. nil will produce a jar ;; with manifest.mf that lacks `Main-Class' property. :main my.service.runner ;; Support project-specific task aliases. These are interpreted in ;; the same way as command-line arguments to the lein command. If ;; the alias points to a vector, it uses partial application. For ;; example, "lein with-magic run -m hi.core" would be equivalent to ;; "lein assoc :magic true run -m hi.core". Remember, commas are not ;; considered to be special by argument parsers, they're just part ;; of the preceding argument. :aliases {"launch" ["run" "-m" "myproject.main"] ;; Values from the project map can be spliced into the arguments ;; using :project/key keywords. "launch-version" ["run" "-m" "myproject.main" :project/version] "dumbrepl" ["trampoline" "run" "-m" "clojure.main/main"] ;; :pass-through-help ensures `lein my-alias help` is not converted ;; into `lein help my-alias`. "go" ^:pass-through-help ["run" "-m"] ;; For complex aliases, a docstring may be attached. The docstring ;; will be printed instead of the expansion when running `lein help`. "deploy!" ^{:doc "Recompile sources, then deploy if tests succeed."} ;; Nested vectors are supported for the "do" task ["do" "clean" ["test" ":integration"] ["deploy" "clojars"]]} ;;; Custom Release Tasks ;; By default `lein release` performs a series of tasks typical of the release ;; process for many Leiningen-managed projects. These tasks can be overridden ;; using `:release-tasks` as follows: :release-tasks [["vcs" "assert-committed"] ["change" "version" "leiningen.release/bump-version" "release"] ["vcs" "commit"] ["vcs" "tag"] ["deploy"]] ;; This differs from the default `:release-tasks` behavior in that it doesn't ;; go on to perform another `change version` or `vcs` task, instead leaving ;; that up to the developer to do manually. ;;; Running Project Code ;; Normally Leiningen runs the javac and compile tasks before ;; calling any eval-in-project code, but you can override this with ;; the :prep-tasks key to do other things like compile protocol buffers. :prep-tasks [["protobuf" "compile"] "javac" "compile"] ;; These namespaces will be AOT-compiled. Needed for gen-class and ;; other Java interop functionality. Put a regex here to compile all ;; namespaces whose names match. If you only need AOT for an uberjar ;; gen-class, put `:aot :all` in the :uberjar profile and see :target-path for ;; how to enable profile-based target isolation. :aot [org.example.sample] ;; Forms to prepend to every form that is evaluated inside your project. ;; Allows working around the Gilardi Scenario: http://technomancy.us/143 ;; Note: This code is not executed in jars or uberjars. :injections [(require 'clojure.pprint)] ;; Java agents can instrument and intercept certain VM features. Include ;; :bootclasspath true to place the agent jar on the bootstrap classpath. :java-agents [[nodisassemble "0.1.1" :options "extra"]] ;; Options to pass to java compiler for java source, ;; exactly the same as command line arguments to javac. :javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"] ;; Emit warnings on all reflection calls. - DEPRECATED (see below) :warn-on-reflection true ;; Sets the values of global vars within Clojure. This example ;; disables all pre- and post-conditions and emits warnings on ;; reflective calls. See the Clojure documentation for the list of ;; valid global variables to set (and their meaningful values). :global-vars {*warn-on-reflection* true *assert* false} ;; Use a different `java` executable for project JVMs. Leiningen's own JVM is ;; set with the LEIN_JAVA_CMD environment variable. :java-cmd "/home/phil/bin/java1.7" ;; You can set JVM-level options here. The :java-opts key is an alias for this. :jvm-opts ["-Xmx1g"] ;; Set the context in which your project code is evaluated. Defaults ;; to :subprocess, but can also be :leiningen (for plugins) or :nrepl ;; to connect to an existing project process over nREPL. A project nREPL ;; server can be started simply by invoking `lein repl`. If no connection ;; can be established, :nrepl falls back to :subprocess. :eval-in :leiningen ;; Enable bootclasspath optimization. This improves boot time but interferes ;; with certain libraries like Jetty that make assumptions about classloaders. :bootclasspath true ;;; Filesystem Paths ;; If you'd rather use a different directory structure, you can set these. ;; Paths that contain "inputs" are string vectors, "outputs" are strings. :source-paths ["src" "src/main/clojure"] :java-source-paths ["src/main/java"] ; Java source is stored separately. :test-paths ["test" "src/test/clojure"] :resource-paths ["src/main/resource"] ; Non-code files included in classpath/jar. ;; All generated files will be placed in :target-path. In order to avoid ;; cross-profile contamination (for instance, uberjar classes interfering ;; with development), it's recommended to include %s in in your custom ;; :target-path, which will splice in names of the currently active profiles. :target-path "target/%s/" ;; Directory in which to place AOT-compiled files. Including %s will ;; splice the :target-path into this value. :compile-path "%s/classy-files" ;; Directory in which to extract native components from inside dependencies. ;; Including %s will splice the :target-path into this value. Note that this ;; is not where to *look* for existing native libraries; use :jvm-opts with ;; -Djava.library.path=... instead for that. :native-path "%s/bits-n-stuff" ;; Directories under which `lein clean` removes files. ;; Specified by keyword or keyword-chain to get-in path in this defproject. ;; Both a single path and a collection of paths are accepted as each. ;; For example, if the other parts of project are like: ;; :target-path "target" ;; :compile-path "classes" ;; :foobar-paths ["foo" "bar"] ;; :baz-config {:qux-path "qux"} ;; :clean-targets below lets `lein clean` remove files under "target", ;; "classes", "foo", "bar", "qux", and "out". ;; By default, will protect paths outside the project root and within standard ;; lein source directories ("src", "test", "resources", "doc", "project.clj"). ;; However, this protection can be overridden with metadata on the :clean-targets ;; vector - ^{:protect false} :clean-targets [:target-path :compile-path :foobar-paths [:baz-config :qux-path] "out"] ;; Workaround for http://dev.clojure.org/jira/browse/CLJ-322 by deleting ;; compilation artifacts for namespaces that come from dependencies. :clean-non-project-classes true ;; Paths to include on the classpath from each project in the ;; checkouts/ directory. (See the tutorial for more details about ;; checkout dependencies.) Set this to be a vector of functions that ;; take the target project as argument. Defaults to [:source-paths ;; :compile-path :resource-paths], but you could use the following ;; to share code from the test suite: :checkout-deps-shares [:source-paths :test-paths ~(fn [p] (str (:root p) "/lib/dev/*"))] ;;; Testing ;; Predicates to determine whether to run a test or not, take test metadata ;; as argument. See `lein help test` for more information. :test-selectors {:default (fn [m] (not (or (:integration m) (:regression m)))) :integration :integration :regression :regression} ;; In order to support the `retest` task, Leiningen must monkeypatch the ;; clojure.test library. This disables that feature and breaks `lein retest`. :monkeypatch-clojure-test false ;;; Repl ;; Options to change the way the REPL behaves. :repl-options { ;; Specify the string to print when prompting for input. ;; defaults to something like (fn [ns] (str *ns* "=> ")) :prompt (fn [ns] (str "your command for <" ns ">? " )) ;; What to print when the repl session starts. :welcome (println "Welcome to the magical world of the repl!") ;; Specify the ns to start the REPL in (overrides :main in ;; this case only) :init-ns foo.bar ;; This expression will run when first opening a REPL, in the ;; namespace from :init-ns or :main if specified. :init (println "here we are in" *ns*) ;; Print stack traces on exceptions (highly recommended, but ;; currently overwrites *1, *2, etc). :caught clj-stacktrace.repl/pst+ ;; Skip's the default requires and printed help message. :skip-default-init false ;; Customize the socket the repl task listens on and ;; attaches to. :host "0.0.0.0" :port 4001 ;; If nREPL takes too long to load it may timeout, ;; increase this to wait longer before timing out. ;; Defaults to 30000 (30 seconds) :timeout 40000 ;; nREPL server customization ;; Only one of #{:nrepl-handler :nrepl-middleware} ;; may be used at a time. ;; Use a different server-side nREPL handler. :nrepl-handler (nrepl.server/default-handler) ;; Add server-side middleware to nREPL stack. :nrepl-middleware [my.nrepl.thing/wrap-amazingness ;; TODO: link to more detailed documentation. ;; Middleware without appropriate metadata ;; (see nrepl.middleware/set-descriptor! ;; for details) will simply be appended to the stack ;; of middleware (rather than ordered based on its ;; expectations and requirements). (fn [handler] (fn [& args] (prn :middle args) (apply handler args)))]} ;;; Jar Output ;; Name of the jar file produced. Will be placed inside :target-path. ;; Including %s will splice the project version into the filename. :jar-name "sample.jar" ;; As above, but for uberjar. :uberjar-name "sample-standalone.jar" ;; Leave the contents of :source-paths out of jars (for AOT projects). :omit-source true ;; Files with names matching any of these patterns will be excluded from jars. :jar-exclusions [#"(?:^|/).svn/"] ;; Files with names matching any of these patterns will included in the jar ;; even if they'd be skipped otherwise. :jar-inclusions [#"^\.ebextensions"] ;; Same as :jar-exclusions, but for uberjars. :uberjar-exclusions [#"META-INF/DUMMY.SF"] ;; By default Leiningen will run a clean before creating jars to prevent ;; undeclared AOT from leaking to downstream consumers; this disables ;; that behaviour. :auto-clean false ;; Files to merge programmatically in uberjars when multiple same-named files ;; exist across project and dependencies. Should be a map of filename strings ;; or regular expressions to a sequence of three functions: ;; 1. Takes an input stream; returns a parsed datum. ;; 2. Takes a new datum and the current result datum; returns a merged datum. ;; 3. Takes an output stream and a datum; writes the datum to the stream. ;; Resolved in reverse dependency order, starting with project. :uberjar-merge-with {#"\.properties$" [slurp str spit]} ;; Add arbitrary jar entries. Supports :path, :paths, :bytes, and :fn types. :filespecs [{:type :path :path "config/base.clj"} ;; Directory paths are included recursively. {:type :paths :paths ["config/web" "config/cli"]} ;; Programmatically-generated content can use :bytes. {:type :bytes :path "project.clj" ;; Strings or byte arrays are accepted. :bytes ~(slurp "project.clj")} ;; :fn filespecs take the project as an argument and ;; should return a filespec map of one of the other types. {:type :fn :fn (fn [p] {:type :bytes :path "git-log" :bytes (:out (clojure.java.shell/sh "git" "log" "-n" "1"))})}] ;; Set arbitrary key/value pairs for the jar's manifest. Any ;; vector or sequence of pairs is supported as well. :manifest {"Project-awesome-level" "super-great" ;; Function values will be called with the project as an argument. "Class-Path" ~#(clojure.string/join \space (leiningen.core.classpath/get-classpath %)) ;; If a value is a collection, a manifest section is built for it and ;; the name of the key is used as the section name. :my-section-1 [["MyKey1" "MyValue1"] ["MyKey2" "MyValue2"]] :my-section-2 {"MyKey3" "MyValue3" "MyKey4" "MyValue4"} ;; Symbol values will be resolved to find a function to call. "Grunge-level" my.plugin/calculate-grunginess} ;;; Pom Output ;; Where the pom.xml is written. If not set, the project root. :pom-location "target/" ;; Set parent for working within a multi-module maven project. :parent [org.example/parent "0.0.1" :relative-path "../parent/pom.xml"] ;; Extensions here will be propagated to the pom but not used by Leiningen. :extensions [[org.apache.maven.wagon/wagon-webdav "1.0-beta-2"] [foo/bar-baz "1.0"]] ;; Plugins here will be propagated to the pom but not used by Leiningen. :pom-plugins [[com.theoryinpractise/clojure-maven-plugin "1.3.13" ;; this section is optional, values have the same syntax as pom-addition {:configuration [:sourceDirectories [:sourceDirectory "src"]] :extensions "true" :executions ([:execution [:id "echodir"] [:goals ([:goal "run"])] [:phase "verify"]])}] [org.apache.tomcat.maven/tomcat7-maven-plugin "2.1"] [com.google.appengine/appengine-maven-plugin "1.9.68" ;; Use a list to pass any structure unaltered (:configuration [:project "foo"] [:version "bar"])]] ;; Include tag in generated pom.xml file. All key/value pairs ;; appear exactly as configured. If absent, Leiningen will try to ;; use information from a .git directory. :scm {:name "git" :tag "098afd745bcd" :url "http://127.0.0.1/git/my-project" ;; Allows you to use a repository in a different directory than the ;; project's root, for instance, if you had multiple projects in a ;; single git repository. :dir ".."} ;; Include xml in generated pom.xml file, as parsed by ;; clojure.data.xml/sexp-as-element. Resulting pom still needs to ;; validate according to the pom XML schema. :pom-addition [:developers [:developer {:id "benbit"} [:name "Ben Bitdiddle"] [:url "http://www.example.com/benjamin"]]] ;;; Safety flags ;; Indicate whether or not `lein install` should abort when trying to install ;; releases. When false, trying to run `lein install` in a project with a version ;; that isn't a snapshot will cause Leiningen to abort with a descriptive error ;; message. :install-releases? false ;; Dictate which git branches deploys should be allowed from. When set, ;; `lein deploy` will only work from the git branches included and will ;; abort otherwise. :deploy-branches ["master"] ;;; Artifact Classifers Installation ;; Option to install classified maven artifacts. A map where keys ;; indicate the classifier name. :classifiers {;; If the value is a map it is merged like a profile :tests {:source-paths ^:replace ["test"]} ;; If a keyword it is looked up from :profiles :classy :my-profile}) ;;; Environment Variables used by Leiningen ;; JAVA_CMD - executable to use for java(1) ;; JVM_OPTS - extra options to pass to the java command ;; DEBUG - increased verbosity ;; LEIN_SILENT - suppress info-level output ;; LEIN_HOME - directory in which to look for user settings ;; LEIN_SNAPSHOTS_IN_RELEASE - allow releases to depend on snapshots ;; LEIN_JVM_OPTS - tweak speed of plugins or fix compatibility with old Java versions ;; LEIN_USE_BOOTCLASSPATH - speed up boot time on JVMs older than 9 ;; LEIN_REPL_HOST - interface on which to connect to nREPL server ;; LEIN_REPL_PORT - port on which to start or connect to nREPL server ;; LEIN_OFFLINE - equivalent of :offline? true but works for plugins ;; LEIN_GPG - gpg executable to use for encryption/signing ;; LEIN_NEW_UNIX_NEWLINES - ensure that `lein new` emits '\n' as newlines ;; LEIN_SUPPRESS_USER_LEVEL_REPO_WARNINGS - suppress "repository in user profile" warnings ;; LEIN_FAST_TRAMPOLINE - memoize `java` invocation command to speed up subsequent trampoline launches ;; LEIN_NO_USER_PROFILES - suppress loading of user and system profiles ;; http_proxy - host and port to proxy HTTP connections through ;; http_no_proxy - pipe-separated list of hosts which may be accessed directly leiningen-2.9.1/src/000077500000000000000000000000001343535564500142775ustar00rootroot00000000000000leiningen-2.9.1/src/leiningen/000077500000000000000000000000001343535564500162475ustar00rootroot00000000000000leiningen-2.9.1/src/leiningen/change.clj000066400000000000000000000146241343535564500201750ustar00rootroot00000000000000(ns leiningen.change "Rewrite project.clj by applying a function." (:require [clojure.string :as str] [clojure.zip :as zip] [clojure.java.io :as io] [leiningen.core.utils :as utils] [leiningen.core.main :as main] [net.cgrand.sjacket :as sj] [net.cgrand.sjacket.parser :as parser])) ;;; Helpers (defn- fail-argument! [msg] (throw (IllegalArgumentException. msg))) ;; NOTE: The metadata will be printed out differently. E.g. ^:replace will be ;; printed as ^{:replace true} -- but at least it is preserved. (defn- clj->sjacket [value] (binding [*print-meta* true] (-> value pr-str parser/parser :content first))) ;; NOTE: this destroy comments, formatting, etc. (defn- sjacket->clj [value] (if-not (#{:comment :whitespace :newline} (:tag value)) (-> value sj/str-pt read-string))) (defn ^:internal normalize-path [value] (if (coll? value) value (map keyword (remove empty? (str/split value #":"))))) (defn ^:internal collapse-fn [f args] (let [f (cond (ifn? f) f (= "set" f) (constantly (first args)) (string? f) (or (utils/require-resolve (symbol f)) (fail-argument! (str "Unable to resolve " f))) :else (fail-argument! (str f " is not a function.")))] #(apply f % args))) ;;; Maven convention helpers (defn- split-name [name] (str/split name #"/" 2)) (defn- get-group-id [name] (let [[group artifact] (split-name name)] group)) (defn- get-artifact-id [name] (let [[group artifact] (split-name name)] (or artifact group))) (defn- set-group-id [new-id name] (let [[group artifact] (split-name name)] (str new-id "/" (or artifact group)))) (defn- set-artifact-id [new-id name] (let [[group artifact] (split-name name)] (if artifact (str group "/" new-id) new-id))) ;;; Traversal (defn- defproject? [loc] (let [{:keys [tag content]} (zip/node loc)] (and (= :name tag) (= ["defproject"] content)))) (defn- insignificant? [loc] (let [{:keys [tag]} (zip/node loc)] (parser/space-nodes tag))) (defn- find-defproject [loc] (->> loc (iterate zip/next) (take-while (comp not zip/end?)) (filter defproject?) first)) (defn- find-right [loc pred] (->> loc (iterate zip/right) (take-while (comp not nil?)) (filter (comp pred zip/node)) first)) (defn- find-key [loc key] (->> loc (iterate zip/right) (take-while (comp not nil?)) (remove insignificant?) (partition 2) (map first) (filter (comp #{key} sjacket->clj zip/node)) first)) (defn- next-value [loc] (->> loc (iterate zip/right) (take-while (comp not nil?)) (drop 1) (remove insignificant?) first)) (defn- parse-project [project-str] (-> (parser/parser project-str) zip/xml-zip find-defproject (or (fail-argument! "Project definition not found")) zip/up)) ;;; Modifiers (defn- insert-entry [loc val] (-> (if-not (= "{" (zip/node (zip/left loc))) (zip/insert-left loc " ") loc) (zip/insert-left (clj->sjacket val)))) (defn- update-version [proj fn] (-> proj (find-right (comp #{:string} :tag)) (or (fail-argument! "Project version not found")) (zip/edit (comp clj->sjacket fn sjacket->clj)) zip/root)) (defn- update-name [proj fn] (-> proj zip/right (find-right (comp #{:symbol} :tag)) (or (fail-argument! "Project name not found")) (zip/edit (comp clj->sjacket symbol fn str sjacket->clj )) zip/root)) (defn- update-setting [proj [p & ath] fn] (let [loc (or (-> proj (find-key p) next-value) (-> proj zip/rightmost (insert-entry p) (insert-entry {}) zip/left))] (if-not (empty? ath) (recur (-> loc zip/down zip/right) ath fn) (zip/root (zip/edit loc (comp clj->sjacket fn sjacket->clj)))))) ;;; Public API (defn change-string "Programmatic functional access to project.clj-rewriting. See the `change` task function which handles reading and writing from disk as well as turning string args into Clojure data; this function handles the rest." [project-str key-or-path f & args] (let [f (collapse-fn f args) path (normalize-path key-or-path) proj (parse-project project-str)] (sj/str-pt (condp = path [:version] (update-version proj f) [:name] (update-name proj f) [:group-id] (update-name proj #(set-group-id (f (get-group-id %)) %)) [:artifact-id] (update-name proj #(set-artifact-id (f (get-artifact-id %)) %)) ;; moving to the right to move past defproject to get nice key-value ;; pairs whitespaces and project name and version are filtered out later (update-setting (zip/right proj) path f))))) (defn change "Rewrite project.clj with f applied to the value at key-or-path. The first argument should be a keyword (or mashed-together keywords for nested values indicating which value to change). The second argument should name a function var which will be called with the current value as its first argument and the remaining task arguments as the rest. This will append \"-SNAPSHOT\" to the current version: $ lein change version str '\"-SNAPSHOT\"' When called programmatically, you may pass a coll of keywords for the first arg or an actual function for the second. Using set as the function argument will set the key directly, rather than applying a function to the original value: $ lein change version set '\"1.0.0\"' All the arguments to f are passed through the reader, so double quoting is necessary to use strings. Note that this task reads the project.clj file from disk rather than honoring the project map, so profile merging or `update-in` invocations will not affect it." [project key-or-path f & args] ;; cannot work with project map, want to preserve formatting, comments, etc (when-not (and (every? string? args) (try (mapv read-string args) (catch Exception _))) (main/abort "Each argument to change task must be a readable string:" (pr-str args))) (let [project-file (io/file (:root project) "project.clj") source (slurp project-file) args (map read-string args)] (spit project-file (apply change-string source key-or-path f args)))) leiningen-2.9.1/src/leiningen/check.clj000066400000000000000000000027721343535564500200260ustar00rootroot00000000000000(ns leiningen.check "Check syntax and warn on reflection." (:require [leiningen.core.eval :as eval] [leiningen.core.main :as main] [bultitude.core :as b] [clojure.java.io :as io])) (defn check "Check syntax and warn on reflection." ([project] (let [source-files (map io/file (:source-paths project)) nses (b/namespaces-on-classpath :classpath source-files :ignore-unreadable? false) action `(let [failures# (atom 0)] (doseq [ns# '~nses] ;; load will add the .clj, so can't use ns/path-for. (let [ns-file# (-> (str ns#) (.replace \- \_) (.replace \. \/))] (binding [*out* *err*] (println "Compiling namespace" ns#)) (try (binding [*warn-on-reflection* true] (load ns-file#)) (catch ExceptionInInitializerError e# (swap! failures# inc) (.printStackTrace e#))))) (if-not (zero? @failures#) (System/exit @failures#)))] (try (binding [eval/*pump-in* false] (eval/eval-in-project project action)) (catch clojure.lang.ExceptionInfo e (main/abort "Failed.")))))) leiningen-2.9.1/src/leiningen/classpath.clj000066400000000000000000000014311343535564500207220ustar00rootroot00000000000000(ns leiningen.classpath "Print the classpath of the current project." (:require [leiningen.core.classpath :as classpath] [leiningen.core.main :as main] [clojure.string :as str]) (:import (org.eclipse.aether.resolution DependencyResolutionException))) (defn get-classpath-string [project] (try (str/join java.io.File/pathSeparatorChar (classpath/get-classpath project)) (catch DependencyResolutionException e (main/abort (.getMessage e))))) (defn classpath "Write the classpath of the current project to output-file. With no arguments, print the classpath to stdout. Suitable for java's -cp option." ([project] (println (get-classpath-string project))) ([project output-file] (spit output-file (get-classpath-string project)))) leiningen-2.9.1/src/leiningen/clean.clj000066400000000000000000000071351343535564500200310ustar00rootroot00000000000000(ns leiningen.clean "Remove all files from project's target-path." (:require [clojure.java.io :as io] [leiningen.core.utils :as utils] [leiningen.core.main :as main]) (:import [java.io IOException])) (defn real-directory? "Returns true if this file is a real directory, false if it is a symlink or a normal file." [f] (if (= :windows (utils/get-os)) (.isDirectory f) (and (.isDirectory f) (not (utils/symlink? f))))) (defn delete-file-recursively "Delete file f. If it's a directory, recursively delete all its contents. Raise an exception if any deletion fails unless silently is true." [f & [silently]] (let [f (io/file f)] (when (real-directory? f) (doseq [child (.listFiles f)] (delete-file-recursively child silently))) (.setWritable f true) (io/delete-file f silently))) (defn- protected-paths "Returns a set of leiningen project source directories and important files." [project] (let [root-dir (:root project)] (->> [:source-paths :java-source-paths :test-paths :resource-paths] (select-keys project) (mapcat val) (list* (io/file root-dir "doc") (io/file root-dir "project.clj")) (map io/file) (map #(.getCanonicalPath %)) set))) (defn- protected-path? "Is path one of the leiningen project files or directories (which we expect to be version controlled), or a descendant?" [project path] (let [protected-paths (protected-paths project)] (or (protected-paths (.getCanonicalPath (io/file path))) (some #(utils/ancestor? % path) protected-paths)))) (defn- protect-clean-targets? "Returns the value of :protect in the metadata map for the :clean-targets value." [project] (-> project :clean-targets meta (get :protect true))) (defn- error-msg [& args] (apply str (concat args "\nCheck :clean-targets" " or override this behavior by adding metadata ->" "\n :clean-targets ^{:protect false} [...targets...]"))) (defn- sanity-check "Ensure that a clean-target string refers to a directory that is sensible to delete." [project clean-target] (when (and (string? clean-target) (protect-clean-targets? project)) (cond (not (utils/ancestor? (:root project) clean-target)) (main/abort (error-msg "Deleting path outside of the project root [\"" clean-target "\"] is not allowed.")) (protected-path? project clean-target) (main/abort (error-msg "Deleting non-target project paths [\"" clean-target "\"] is not allowed."))))) (defn- with-parent-target-path "Assoc the :target-path sans the profile suffix, if any format specifier is detected in the raw :target-path" [project] (if-let [tp (->> project meta :without-profiles :target-path (re-find #"(.*?)/[^/]*%") second)] (assoc project :target-path (if (.isAbsolute (io/file tp)) tp (str (io/file (:root project) tp)))) project)) (defn clean "Removes all files from paths in clean-targets for a project" [project] (let [project (with-parent-target-path project)] (doseq [target-key (:clean-targets project)] (when-let [target (cond (vector? target-key) (get-in project target-key) (keyword? target-key) (target-key project) (string? target-key) target-key)] (doseq [f (flatten [target])] (sanity-check project f) (delete-file-recursively f :silently)))))) leiningen-2.9.1/src/leiningen/compile.clj000066400000000000000000000164311343535564500203760ustar00rootroot00000000000000(ns leiningen.compile "Compile Clojure source into .class files." (:require [leiningen.core.eval :as eval] [leiningen.core.main :as main] [bultitude.core :as b] [clojure.java.io :as io]) (:refer-clojure :exclude [compile]) (:import (java.io PushbackReader File))) (defn regex? [str-or-re] (instance? java.util.regex.Pattern str-or-re)) (defn- matching-nses [re-or-sym namespaces] (if (regex? re-or-sym) (filter #(re-find re-or-sym (name %)) namespaces) [re-or-sym])) (defn- find-namespaces-by-regex [project nses] (let [avail-nses (->> (:source-paths project) (map io/file) (b/namespaces-on-classpath :classpath) (sort))] (mapcat #(matching-nses % avail-nses) nses))) (defn compilable-namespaces "Returns a seq of the namespaces that are compilable, regardless of whether their class files are present and up-to-date." [{:keys [aot source-paths] :as project}] (if (or (= :all aot) (= [:all] aot)) (sort (b/namespaces-on-classpath :classpath (map io/file source-paths))) (find-namespaces-by-regex project aot))) (defn stale-namespaces "Return a seq of namespaces that are both compilable and that have missing or out-of-date class files." [project] (for [namespace (compilable-namespaces project) :let [[rel-source source] (or (first (for [source-path (:source-paths project) rel-source (map (partial b/path-for namespace) ["clj" "cljc"]) :let [file (io/file source-path rel-source)] :when (.exists ^File file)] [rel-source file])) (let [rel-source (b/path-for namespace)] ;; always return a source file location (#1205) [rel-source (io/file (first (:source-paths project)) rel-source)]))] :when source :let [rel-compiled (.replaceFirst rel-source "\\.cljc?$" "__init.class") compiled (io/file (:compile-path project) rel-compiled)] :when (>= (.lastModified source) (.lastModified compiled))] namespace)) ;; .class file cleanup (defn- package-in-project? "Tests if the package found in the compile path exists as a directory in the source path." [found-path compile-path source-path] (.isDirectory (io/file (.replace found-path compile-path source-path)))) (defn- has-source-package? "Test if the class file's package exists as a directory in source-paths." [project f source-paths] (and source-paths (let [[[parent] [_ _ proxy-mod-parent]] (->> f, (iterate #(.getParentFile %)), (take-while identity), rest, (split-with #(not (re-find #"^proxy\$" (.getName %))))) found-path (.getPath (or proxy-mod-parent parent)) compile-path (:compile-path project)] (some #(package-in-project? found-path compile-path %) source-paths)))) (defn- source-in-project? "Tests if a file found in the compile path exists in the source path." [parent compile-path source-path] (let [path (.replace parent compile-path source-path)] (or (.exists (io/file (str path ".clj"))) (.exists (io/file (str path ".cljc")))))) (defn- class-in-project? [project f] (or (has-source-package? project f (:source-paths project)) (has-source-package? project f (:java-source-paths project)) (let [parent (.getParent f) compile-path (:compile-path project)] (some #(source-in-project? parent compile-path %) (:source-paths project))))) (defn- relative-path [project f] (let [root-length (if (= \/ (last (:compile-path project))) (count (:compile-path project)) (inc (count (:compile-path project))))] (subs (.getAbsolutePath f) root-length))) (defn- blacklisted-class? [project f] ;; true indicates all non-project classes are blacklisted (or (true? (:clean-non-project-classes project)) (some #(re-find % (relative-path project f)) (:clean-non-project-classes project)))) (defn- whitelisted-class? [project f] (or (class-in-project? project f) (and (:class-file-whitelist project) (re-find (:class-file-whitelist project) (relative-path project f))))) (defn clean-non-project-classes [project] (when (:clean-non-project-classes project) (doseq [f (file-seq (io/file (:compile-path project))) :when (and (.isFile f) (not (whitelisted-class? project f)) (blacklisted-class? project f))] (.delete f)))) (defn compilation-specs [cli-args] (if (contains? #{[:all] [":all"]} cli-args) [:all] (->> cli-args (map #(if (string? %) (read-string %) %)) (sort-by (comp not regex?))))) (def ^:private thread-factory-form `(let [counter# (atom 0)] (proxy [java.util.concurrent.ThreadFactory] [] (newThread [r#] (let [thread-factory# (java.util.concurrent.Executors/defaultThreadFactory)] (doto (.newThread thread-factory# r#) (.setName (str "leiningen-send-off-pool-" (swap! counter# inc))))))))) (def ^:private set-agent-threadpool-form ;; set-agent-send-off-executor! was introduced in Clojure 1.5 `(when-let [set-executor!# (resolve 'clojure.core/set-agent-send-off-executor!)] (set-executor!# (doto ^java.util.concurrent.ThreadPoolExecutor (java.util.concurrent.Executors/newCachedThreadPool ~thread-factory-form) (.setKeepAliveTime 100 java.util.concurrent.TimeUnit/MILLISECONDS))))) (defn compile "Compile Clojure source into .class files. Uses the namespaces specified under :aot in project.clj or those given as command-line arguments. Use :all argument to compile everything. Pass #\"regular expressions\" to compile any matching namespaces. You may need to escape punctuation for your shell. This should automatically happen when required if it's configured correctly; it shouldn't need to be manually invoked. See the javac task as well. Compiling code loads the namespace, so keep side-effects out of the top level. Code that should run on startup belongs in a -main defn." ([project] (if-let [namespaces (seq (stale-namespaces project))] (let [ns-sym (gensym "namespace") form `(do ~set-agent-threadpool-form (doseq [~ns-sym '~namespaces] ~(when main/*info* `(binding [*out* *err*] (println "Compiling" ~ns-sym))) (try (clojure.core/compile ~ns-sym) (catch Throwable t# (binding [*out* *err*] (println (.getMessage t#))) (throw t#))))) project (update-in project [:prep-tasks] (partial remove #{"compile"}))] (try (binding [eval/*eval-print-dup* true] (eval/eval-in-project project form)) (catch Exception e (main/abort "Compilation failed:" (.getMessage e))) (finally (clean-non-project-classes project)))) (main/debug "All namespaces already AOT compiled."))) ([project & args] (compile (assoc project :aot (compilation-specs args))))) leiningen-2.9.1/src/leiningen/deploy.clj000066400000000000000000000226021343535564500202370ustar00rootroot00000000000000(ns leiningen.deploy "Build and deploy jar to remote repository." (:require [cemerick.pomegranate.aether :as aether] [leiningen.core.classpath :as classpath] [leiningen.core.main :as main] [leiningen.core.eval :as eval] [leiningen.core.user :as user] [leiningen.core.utils :as utils] [clojure.java.io :as io] [leiningen.pom :as pom] [leiningen.jar :as jar] [clojure.java.shell :as sh] [clojure.string :as string])) (defn- abort-message [message] (cond (re-find #"Return code is 405" message) (str message "\n" "Ensure you are deploying over SSL.") (re-find #"Return code is 401" message) (str message "\n" "See `lein help deploying` for an explanation of how" " to specify credentials.") :else message)) (defn add-auth-from-url [[id settings]] (let [url (utils/build-url id) user-info (and url (.getUserInfo url)) [username password] (and user-info (.split user-info ":"))] (if username [id (assoc settings :username username :password password)] [id settings]))) (defn add-auth-interactively [[id settings]] (if (or (and (:username settings) (some settings [:password :passphrase :private-key-file])) (:no-auth settings) (re-find #"(file|scp|scpexe)://" (:url settings))) [id settings] (do (when @utils/rebound-io? (main/abort "No credentials found for " id "(did you mean `lein deploy" "clojars`?)\nPassword prompts are not supported when ran" "after other (potentially)\ninteractive tasks.\nSee `lein" "help deploy` for an explanation of how to specify" "credentials.")) (print "No credentials found for" id) (when (not= "clojars" id) (print "(did you mean `lein deploy clojars`?)")) (println "\nSee `lein help deploying` for how to configure credentials" "to avoid prompts.") (print "Username: ") (flush) (let [username (read-line) console (System/console) password (if console (.readPassword console "%s" (into-array ["Password: "])) (do (println "LEIN IS UNABLE TO TURN OFF ECHOING, SO" "THE PASSWORD IS PRINTED TO THE CONSOLE") (print "Password: ") (flush) (read-line)))] [id (assoc settings :username username :password password)])))) ;; repo names must not contain path delimiters because they're used by ;; aether for form filenames (defn- sanitize-repo-name [name] (last (.split name "/"))) (defn repo-for [project name] (let [settings (merge (get (into {} (:repositories project)) name) (get (into {} (:deploy-repositories project)) name))] (-> [(sanitize-repo-name name) (or settings {:url name})] (classpath/add-repo-auth) (add-auth-from-url) (add-auth-interactively)))) (defn signing-args "Produce GPG arguments for signing a file." [file opts] (let [key-spec (if-let [key (:gpg-key opts)] ["--default-key" key])] `["--yes" "-ab" ~@key-spec "--" ~file])) (defn sign "Create a detached signature and return the signature file name." [file opts] (let [{:keys [err exit]} (apply user/gpg (signing-args file opts))] (when-not (zero? exit) (main/abort "Could not sign" (str file "\n" err (if err "\n") "\nSee `lein help gpg` for how to set up gpg.\n" "If you don't expect people to need to verify the " "authorship of your jar, you\ncan add `:sign-releases " "false` to the relevant `:deploy-repositories` entry."))) (str file ".asc"))) (defn signature-for-artifact [[coords artifact-file] opts] {(apply concat (update-in (apply hash-map coords) [:extension] #(str (or % "jar") ".asc"))) (sign artifact-file opts)}) (defn signatures-for-artifacts "Creates and returns the list of signatures for the artifacts needed to be signed." [artifacts sig-opts] (let [total (count artifacts)] (println "Need to sign" total "files with GPG") (doall (map-indexed (fn [idx [coords artifact-file :as artifact]] (printf "[%d/%d] Signing %s with GPG\n" (inc idx) total artifact-file) (flush) (signature-for-artifact artifact sig-opts)) artifacts)))) (defn sign-for-repo? "Generally sign artifacts for this repo?" [repo] (:sign-releases (second repo) true)) (defn signing-opts "Extract signing options map from a project." [project repo] (merge (:signing project) (:signing (second repo)))) (defn files-for [project repo] (let [signed? (sign-for-repo? repo) ;; If pom is put in "target/", :auto-clean true will remove it if the ;; jar is created afterwards. So make jar first, then pom. artifacts (merge (jar/jar project) {[:extension "pom"] (pom/pom project)}) sig-opts (signing-opts project repo)] (if (and signed? (not (.endsWith (:version project) "-SNAPSHOT"))) (reduce merge artifacts (signatures-for-artifacts artifacts sig-opts)) artifacts))) (defn warn-missing-metadata [project] (doseq [key [:description :license :url]] (when (or (nil? (project key)) (re-find #"FIXME" (str (project key)))) (main/warn "WARNING: please set" key "in project.clj.")))) (defn- in-branches [branches] (-> (sh/sh "git" "rev-parse" "--abbrev-ref" "HEAD") :out butlast string/join branches not)) (defn- extension [f] (if-let [[_ signed-extension] (re-find #"\.([a-z]+\.asc)$" f)] signed-extension (if (= "pom.xml" (.getName (io/file f))) "pom" (last (.split f "\\."))))) (defn classifier "The classifier is be located between the version and extension name of the artifact. See http://maven.apache.org/plugins/maven-deploy-plugin/examples/deploying-with-classifiers.html " [version f] (let [pattern (re-pattern (format "%s-(\\p{Alnum}*)\\.%s" version (extension f))) [_ classifier-of] (re-find pattern f)] (when-not (empty? classifier-of) classifier-of))) (defn- fail-on-empty-project [project] (when-not (:root project) (main/abort "Couldn't find project.clj, which is needed for deploy task"))) (defn ^:no-project-needed deploy "Deploy jar and pom to remote repository. The target repository will be looked up in :repositories in project.clj: :repositories [[\"snapshots\" \"https://internal.repo/snapshots\"] [\"releases\" \"https://internal.repo/releases\"] [\"alternate\" \"https://other.server/repo\"]] If you don't provide a repository name to deploy to, either \"snapshots\" or \"releases\" will be used depending on your project's current version. You may provide a repository URL instead of a name. See `lein help deploying` under \"Authentication\" for instructions on how to configure your credentials so you are not prompted on each deploy. You can also deploy arbitrary artifacts from disk: $ lein deploy myrepo com.blueant/fancypants 1.0.1 fancypants.jar pom.xml The repository can be defined in defproject or a profile, or it can be a URL. Use file://$HOME/.m2/repository to install in the local repo. While this works with any arbitrary files on disk, downstream projects will not be able to depend on jars that are deployed without a pom." ([project] (deploy project (if (pom/snapshot? project) "snapshots" "releases"))) ([project repository] (fail-on-empty-project project) (let [branches (set (:deploy-branches project))] (when (and (seq branches) (in-branches branches)) (apply main/abort "Can only deploy from branches listed in" ":deploy-branches:" branches))) (warn-missing-metadata project) (let [repo (repo-for project repository) files (files-for project repo)] (try (java.lang.System/setProperty "aether.checksums.forSignature" "true") (main/debug "Deploying" files "to" repo) (aether/deploy :coordinates [(symbol (:group project) (:name project)) (:version project)] :artifact-map files :transfer-listener :stdout :repository [repo]) (catch org.eclipse.aether.deployment.DeploymentException e (when main/*debug* (.printStackTrace e)) (main/abort (abort-message (.getMessage e))))))) ([project repository identifier version & files] (let [identifier (symbol identifier) artifact-id (name identifier) group-id (namespace identifier) repo (repo-for project repository) artifacts (for [f files] [[:extension (extension f) :classifier (classifier version f)] f])] (java.lang.System/setProperty "aether.checksums.forSignature" "true") (main/debug "Deploying" files "to" repo) (aether/deploy :coordinates [(symbol group-id artifact-id) version] :artifact-map (into {} artifacts) :transfer-listener :stdout :repository [repo] :local-repo (:local-repo project))))) leiningen-2.9.1/src/leiningen/deps.clj000066400000000000000000000157151343535564500177050ustar00rootroot00000000000000(ns leiningen.deps "Download all dependencies." (:require [leiningen.core.classpath :as classpath] [leiningen.core.main :as main] [leiningen.core.project :as project] [leiningen.core.user :as user] [clojure.pprint :as pprint] [leiningen.core.utils :as utils] [cemerick.pomegranate.aether :as aether]) (:import (org.eclipse.aether.resolution DependencyResolutionException))) (defn- walk-deps ([deps f level] (doseq [[dep subdeps] deps] (f dep level) (when subdeps (walk-deps subdeps f (inc level))))) ([deps f] (walk-deps deps f 0))) (defn- print-dep [dep level] (println (apply str (repeat (* 2 level) \space)) (pr-str dep))) (defn- print-path [steps] (doseq [[dep version level] steps] (print-dep [dep version] level))) (defn- why-deps ([deps target path] (doseq [[[dep version] subdeps] deps] (when (= target dep) (doall (map-indexed #(println (apply str (repeat %1 " ")) %2) (conj path [dep version])))) (when subdeps (why-deps subdeps target (conj path [dep version]))))) ([deps target] (why-deps deps target []))) (declare check-signature) (defn- fetch-key [signature err] (if (or (re-find #"Can't check signature: public key not found" err) (re-find #"Can't check signature: No public key" err)) (let [key (second (re-find #"using \w+ key ID (.+)" err)) {:keys [exit]} (user/gpg "--recv-keys" "--" key)] (if (zero? exit) (check-signature signature) :no-key)) :bad-signature)) (defn- check-signature [signature] (let [{:keys [err exit]} (user/gpg "--verify" "--" (str signature))] (if (zero? exit) :signed ; TODO distinguish between signed and trusted (fetch-key signature err)))) (defn- get-signature [project dep] (let [dep-map (assoc (apply hash-map (drop 2 dep)) ;; TODO: check pom signature too :extension "jar.asc") dep (into (vec (take 2 dep)) (apply concat dep-map))] (try (->> (aether/resolve-dependencies :repositories (:repositories project) :mirrors (:mirrors project) :coordinates [dep]) (aether/dependency-files) (filter #(.endsWith (.getName %) ".asc")) (first)) (catch DependencyResolutionException _)))) (defn- verify [project dep _] (let [signature (get-signature project dep) status (if signature (check-signature signature) :unsigned)] ;; TODO: support successful exit code only on fully-signed deps (println status (pr-str dep)))) (def tree-command "A mapping from the tree-command to the dependency key it should print a tree for." {":tree" [:dependencies :managed-dependencies] ":tree-data" [:dependencies :managed-dependencies] ":plugin-tree" [:plugins nil]}) (defn print-implicits [project type] (when-let [implicits (seq (filter utils/require-resolve (project/plugin-vars project type)))] (println (str "Implicit " (name type) ":")) (doseq [i implicits] (println " " i)))) (defn query [project artifact version-string] (->> (assoc project :query [[(symbol artifact) version-string]]) (classpath/get-dependencies :query nil) keys first second println)) (defn deps "Show details about dependencies. lein deps :tree Show the full dependency tree for the current project. Each dependency is only shown once within a tree. lein deps :tree-data Show the full dependency tree as above, but in EDN format. lein deps :plugin-tree Show the full dependency tree for the plugins in the current project. lein deps :verify Check signatures of each dependency. ALPHA: subject to change. lein deps :implicits List the implicit middleware and hooks that will be activated by the current set of plugins. Useful for debugging unexplained behaviour. lein deps :why org.clojure/core.logic Show just the path in the dependency tree directly relating to why a specific dependency has been included. lein deps :query circleci/circleci.test 0.3.0-SNAPSHOT Look up the version number for a dependency in the remote repositories and print a resolved version. If omitted, the version defaults to \"RELEASE\". Can resolve SNAPSHOT versions to timestamps. lein deps Force Leiningen to download the dependencies it needs. This usage is deprecated as it should happen automatically on demand. Normally snapshot dependencies will be checked once every 24 hours; to force them to be updated, use `lein -U $TASK`." ([project] (deps project nil)) ([project command] (try (cond (= ":implicits" command) (do (print-implicits project :middleware) (print-implicits project :hooks)) (tree-command command) (let [project (project/merge-profiles project [{:pedantic? (quote ^:displace warn)}]) [dependencies-key managed-dependencies-key] (tree-command command) hierarchy (classpath/managed-dependency-hierarchy dependencies-key managed-dependencies-key project)] (case command ":tree" (walk-deps hierarchy print-dep) ":plugin-tree" (walk-deps hierarchy print-dep) ":tree-data" (binding [*print-length* 10000 *print-level* 10000] (pprint/pprint hierarchy)))) (= command ":verify") (if (user/gpg-available?) (walk-deps (classpath/managed-dependency-hierarchy :dependencies :managed-dependencies project) (partial verify project)) (main/abort (str "Could not verify - gpg not available.\n" "See `lein help gpg` for how to setup gpg."))) (empty? command) (classpath/resolve-managed-dependencies :dependencies :managed-dependencies project) :else (main/abort "Unknown deps command" command)) (catch DependencyResolutionException e (main/abort (.getMessage e))))) ([project command target] (cond (= command ":query") (deps project command target "RELEASE") (re-find #"^:why+$" command) (why-deps (classpath/managed-dependency-hierarchy :dependencies :managed-dependencies project) (symbol target)) :else (main/abort "Unknown deps command" command))) ([project command artifact version-string] (when (not= ":query" command) (main/abort "Unknown deps command" command)) (query project artifact version-string))) leiningen-2.9.1/src/leiningen/do.clj000066400000000000000000000023501343535564500173430ustar00rootroot00000000000000(ns leiningen.do "Higher-order task to perform other tasks in succession." (:refer-clojure :exclude [do]) (:require [leiningen.core.main :as main])) (defn- conj-to-last [coll x] (update-in coll [(dec (count coll))] conj x)) (defn- butlast-char "Removes the last character in the string." [s] (subs s 0 (dec (count s)))) (defn- pop-if-last "Pops the collection if (pred (peek coll)) is truthy." [coll pred] (if (pred (peek coll)) (pop coll) coll)) (defn ^:internal group-args ([args] (-> (reduce group-args [[]] args) (pop-if-last empty?))) ([groups arg] (cond (coll? arg) (-> (pop-if-last groups empty?) (conj arg [])) (.endsWith arg ",") (-> groups (conj-to-last (butlast-char arg)) (conj [])) :else (conj-to-last groups arg)))) (defn ^:no-project-needed ^:higher-order do "Higher-order task to perform other tasks in succession. Each comma-separated group should be a task name followed by optional arguments. USAGE: lein do test, compile :all, deploy private-repo" [project & args] (doseq [arg-group (group-args args)] (main/resolve-and-apply project arg-group))) leiningen-2.9.1/src/leiningen/help.clj000066400000000000000000000170251343535564500176760ustar00rootroot00000000000000(ns leiningen.help "Display a list of tasks or help for a given task." (:require [clojure.string :as string] [clojure.java.io :as io] [leiningen.core.main :as main] [bultitude.core :as b])) (def docstrings (memoize (fn [] (apply hash-map (mapcat (juxt second b/doc-from-ns-form) (b/namespace-forms-on-classpath :prefix "leiningen")))))) (def ^{:private true :doc "Width of task name column in list of tasks produced by help task."} task-name-column-width 20) (defn- get-arglists [task] (for [args (or (:help-arglists (meta task)) (:arglists (meta task)))] (vec (remove #(= 'project %) args)))) (def ^:private help-padding 3) (defn- formatted-docstring [command docstring padding] (apply str (replace {\newline (apply str (cons \newline (repeat (+ padding (count command)) \space)))} docstring))) (defn- formatted-help [command docstring longest-key-length] (let [padding (+ longest-key-length help-padding (- (count command)))] (format (str "%1s" (apply str (repeat padding \space)) "%2s") command (formatted-docstring command docstring padding)))) (defn- get-subtasks-and-docstrings-for [task] (into {} (map (fn [subtask] (let [m (meta subtask)] [(str (:name m)) (first (.split (:doc m "") "\n"))])) (:subtasks (meta task))))) (defn subtask-help-for [task-ns task] (if-let [subtasks (seq (get-subtasks-and-docstrings-for task))] (let [longest-key-length (apply max (map count (keys subtasks)))] (string/join "\n" (concat ["\n\nSubtasks available:"] (for [[subtask doc] subtasks] (formatted-help subtask doc longest-key-length)) [(str "\nRun `lein help " (:name (meta task)) " $SUBTASK` for subtask details.")]))))) (defn- resolve-task [task-name] (try (let [task-ns (doto (symbol (str "leiningen." task-name)) require) task (ns-resolve task-ns (symbol task-name))] [task-ns task]) (catch java.io.FileNotFoundException e [nil nil]))) (defn- resolve-subtask [task-name subtask-name] (let [[_ task] (resolve-task task-name)] (some #(if (= (symbol subtask-name) (:name (meta %))) %) (:subtasks (meta task))))) (defn- clean-static-help "Returns a string containing help content. Removes doctoc comments if they are present." [help-text] (let [doctoc-text ""] (if (string/includes? help-text doctoc-text) (string/triml (second (string/split help-text (re-pattern doctoc-text)))) help-text))) (defn- static-help [name] (if-let [resource (io/resource (format "leiningen/help/%s" name))] (clean-static-help (slurp resource)))) (declare help-for) (defn- alias-help "Returns a string containing help for an alias, or nil if the string is not an alias." [aliases task-name] (if (aliases task-name) (let [alias-expansion (aliases task-name) explanation (-> alias-expansion meta :doc)] (cond explanation (str task-name ": " explanation) (string? alias-expansion) (str (format (str "'%s' is an alias for '%s'," " which has following help doc:\n") task-name alias-expansion) (help-for alias-expansion)) :no-explanation-or-string (str task-name " is an alias, expands to " alias-expansion))))) (defn help-for "Returns a string containing help for a task. Looks for a function named 'help' in the subtask's namespace, then a docstring on the task, then a docstring on the task ns." ([task-name] (let [[task-ns task] (resolve-task task-name)] (if task (let [help-fn (ns-resolve task-ns 'help)] (str (or (and (not= task-ns 'leiningen.help) help-fn (help-fn)) (:doc (meta task)) (:doc (meta (find-ns task-ns)))) (subtask-help-for task-ns task) (if (some seq (get-arglists task)) (str "\n\nArguments: " (pr-str (get-arglists task)))))) (format "Task: '%s' not found" task-name)))) ([project task-name] (let [aliases (merge main/aliases (:aliases project))] (or (alias-help aliases task-name) (help-for task-name))))) (defn help-for-subtask "Returns a string containing help for a subtask. Looks for a function named 'help-' in the subtask's namespace, using the subtask's docstring if the help function is not found." ([task-name subtask-name] (if-let [subtask (resolve-subtask task-name subtask-name)] (let [subtask-meta (meta subtask) help-fn (ns-resolve (:ns subtask-meta) (symbol (str "help-" subtask-name))) arglists (get-arglists subtask)] (str (or (and help-fn (help-fn)) (:doc subtask-meta)) (if (some seq arglists) (str "\n\nArguments: " (pr-str arglists))))) (format "Subtask: '%s %s' not found" task-name subtask-name))) ([project task-name subtask-name] (let [aliases (merge main/aliases (:aliases project))] (help-for-subtask (aliases task-name task-name) subtask-name)))) (defn help-summary-for [task-ns] (try (let [task-name (last (.split (name task-ns) "\\."))] ;; Use first line of task docstring if ns metadata isn't present (str task-name (apply str (repeat (- task-name-column-width (count task-name)) " ")) (or (task-ns (docstrings)) (first (.split (help-for {} task-name) "\n"))))) (catch Throwable e (binding [*out* *err*] (str task-ns " Problem loading: " (.getMessage e)))))) (defn ^:no-project-needed ^:higher-order help "Display a list of tasks or help for a given task or subtask. Also provides readme, faq, tutorial, news, sample, profiles, deploying, mixed-source, templates, and copying info." ([project task subtask] (println (or (static-help (str task "-" subtask)) (help-for-subtask project task subtask)))) ([project task] (println (or (static-help task) (help-for project task)))) ([project] (println "Leiningen is a tool for working with Clojure projects.\n") (println "Several tasks are available:") (doseq [task-ns (main/tasks)] (println (help-summary-for task-ns))) (println "\nRun `lein help $TASK` for details.") (println "\nGlobal Options:") (println " -o Run a task offline.") (println " -U Run a task after forcing update of snapshots.") (println " -h, --help Print this help or help for a specific task.") (println " -v, --version Print Leiningen's version.") (when-let [aliases (:aliases project)] (println "\nThese aliases are available:") (doseq [[k v] aliases] (if-let [explanation (-> v meta :doc)] (println (str k ": " explanation)) (println (str k ", expands to " v))))) (println "\nSee also: readme, faq, tutorial, news, sample, profiles," "deploying, gpg,\nmixed-source, templates, and copying."))) leiningen-2.9.1/src/leiningen/install.clj000066400000000000000000000023341343535564500204110ustar00rootroot00000000000000(ns leiningen.install "Install the current project to the local repository." (:require [cemerick.pomegranate.aether :as aether] [leiningen.core.project :as project] [leiningen.core.main :as main] [leiningen.jar :as jar] [leiningen.pom :as pom] [clojure.java.io :as io]) (:import (java.util.jar JarFile) (java.util UUID))) (defn install "Install jar and pom to the local repository; typically ~/.m2. In order to install arbitrary files into a repository see the deploy task." [project] (when (not (or (:install-releases? project true) (pom/snapshot? project))) (main/abort "Can't install release artifacts when :install-releases?" "is set to false.")) (let [jarfiles (jar/jar project) pomfile (pom/pom project) local-repo (:local-repo project)] (aether/install :coordinates [(symbol (:group project) (:name project)) (:version project)] :artifact-map jarfiles :pom-file (io/file pomfile) :local-repo local-repo) (main/info (str "Installed jar and pom into " (if local-repo local-repo "local repo") ".")))) leiningen-2.9.1/src/leiningen/jar.clj000066400000000000000000000350771343535564500175310ustar00rootroot00000000000000(ns leiningen.jar "Package up all the project's files into a jar file." (:require [leiningen.pom :as pom] [leiningen.clean :as clean] [leiningen.compile :as compile] [leiningen.core.project :as project] [leiningen.core.eval :as eval] [leiningen.core.main :as main] [leiningen.core.utils :as utils] [bultitude.core :as b] [clojure.set :as set] [clojure.string :as string] [clojure.java.io :as io]) (:import (java.util.jar Manifest JarEntry JarOutputStream) (java.io BufferedOutputStream FileOutputStream ByteArrayInputStream))) (def ^:deprecated whitelist-keys "Deprecated: use leiningen.core.project/whitelist-keys instead" project/whitelist-keys) (defn- unix-path [path] (.replace path "\\" "/")) (defn- default-manifest [project] {"Created-By" (str "Leiningen " (main/leiningen-version)) "Built-By" (System/getProperty "user.name") "Build-Jdk" (System/getProperty "java.version") "Leiningen-Project-ArtifactId" (:name project) "Leiningen-Project-GroupId" (:group project) "Leiningen-Project-Version" (:version project)}) (declare ^:private manifest-entry) (defn- manifest-entries [project manifest-seq] (map (partial manifest-entry project) manifest-seq)) (defn- manifest-entry [project [k v]] (cond (symbol? v) (manifest-entry project [k (resolve v)]) (fn? v) (manifest-entry project [k (v project)]) (coll? v) (->> v ;; Sub-manifest = manifest section (manifest-entries project) (cons (str "\nName: " (name k) "\n")) (string/join)) :else (->> (str (name k) ": " v) (partition-all 70) ;; Manifest spec says lines <= 72 chars (map (partial apply str)) (string/join "\n ") ;; Manifest spec says join with "\n " (format "%s\n")))) (defn- place-sections-last "Places sections at the end of the manifest seq, as specified by the Manifest spec. Retains ordering otherwise (if mf is ordered)." [mf] (sort-by val (fn [v1 v2] (and (not (coll? v1)) (coll? v2))) (seq mf))) (defn ^:internal make-manifest [project] (let [project-manifest (into {} (:manifest project)) default-manifest' (cond-> (default-manifest project) ;; Add default "Main-Class" only if :main is not ;; explicitly set to nil (:main project :not-found) (assoc "Main-Class" (munge (str (:main project 'clojure.main)))))] (->> (merge default-manifest' project-manifest) ;; manifest's "Main-Class" always overrides default "Main-Class" place-sections-last (manifest-entries project) (cons "Manifest-Version: 1.0\n") ;; Manifest-Version line must be first (string/join "") .getBytes ByteArrayInputStream. Manifest.))) (defn ^:internal manifest-map [manifest] (let [attrs (.getMainAttributes manifest)] (zipmap (map str (keys attrs)) (vals attrs)))) (defn- added-file? "Returns true if the file is already added to the jar, false otherwise. Prints a warning if the file is not a directory." [file relative-path added-paths] ;; Path may be blank if it is the root path (if (or (string/blank? relative-path) (added-paths relative-path)) (do (when-not (.isDirectory file) (main/info "Warning: skipped duplicate file:" relative-path)) true))) (defn- skip-file? "Skips the file if it doesn't exist. If the file is not the root-file (specified by :path), will also skip it if it is a dotfile, emacs backup file or matches an exclusion pattern." [file relative-path root-file exclusion-patterns inclusion-patterns] (or (not (.exists file)) (and (not= file root-file) (not (some #(re-find % relative-path) inclusion-patterns)) (or (re-find #"^\.?#" (.getName file)) (re-find #"~$" (.getName file)) (some #(re-find % relative-path) exclusion-patterns))))) (defmulti ^:private copy-to-jar (fn [project jar-os acc spec] (:type spec))) (defn- relativize-path "Relativizes a path: Removes the root-path of a path if not already removed." [path root-path] (if (.startsWith path root-path) (.substring path (.length root-path)) path)) (defn- full-path ;; Q: is this a good name for this action? "Appends the path string with a '/' if the file is a directory." [file path] (if (.isDirectory file) (str path "/") path)) (defn- dir-string "Returns the file's directory as a string, or the string representation of the file itself if it is a directory." [file] (if-not (.isDirectory file) (str (.getParent file) "/") (str file "/"))) (defn- put-jar-entry! "Adds a jar entry to the Jar output stream." [jar-os file path] (.putNextEntry jar-os (doto (JarEntry. path) (.setTime (.lastModified file)))) (when-not (.isDirectory file) (io/copy file jar-os))) (defmethod copy-to-jar :path [project jar-os acc spec] (let [root-file (io/file (:path spec)) root-dir-path (unix-path (dir-string root-file)) paths (for [child (file-seq root-file) :let [path (relativize-path (full-path child (unix-path (str child))) root-dir-path)]] (when-not (or (skip-file? child path root-file (:jar-exclusions project) (:jar-inclusions project)) (added-file? child path acc)) (put-jar-entry! jar-os child path) path))] (into acc paths))) (defmethod copy-to-jar :paths [project jar-os acc spec] (reduce (partial copy-to-jar project jar-os) acc (for [path (:paths spec)] {:type :path :path path}))) (defmethod copy-to-jar :bytes [project jar-os acc spec] (let [path (unix-path (:path spec))] (when-not (some #(re-find % path) (:jar-exclusions project)) (.putNextEntry jar-os (JarEntry. path)) (let [bytes (if (string? (:bytes spec)) (.getBytes (:bytes spec)) (:bytes spec))] (io/copy (ByteArrayInputStream. bytes) jar-os))) (conj acc path))) (defmethod copy-to-jar :fn [project jar-os acc spec] (let [f (eval (:fn spec)) dynamic-spec (f project)] (copy-to-jar project jar-os acc dynamic-spec))) (defn write-jar [project out-file filespecs] (with-open [jar-os (-> out-file (FileOutputStream.) (BufferedOutputStream.) (JarOutputStream. (make-manifest project)))] (let [jar-paths (reduce (partial copy-to-jar project jar-os) #{} filespecs)] (if (:main project) (let [main-path (str (-> (string/replace (:main project) "." "/") (string/replace "-" "_")) ".class")] (when-not (some #{main-path} jar-paths) (main/info "Warning: The Main-Class specified does not exist" "within the jar. It may not be executable as expected." "A gen-class directive may be missing in the namespace" "which contains the main method, or the namespace has not" "been AOT-compiled.")))) jar-paths))) ;; TODO: change in 3.0; this is hideous (defn- filespecs [project] (let [root-files (.list (io/file (:root project))) readmes (filter (partial re-find #"^(?i)readme") root-files) licenses (filter (partial re-find #"^(?i)license") root-files) scope (partial format "META-INF/leiningen/%s/%s/%s" (:group project) (:name project))] (concat [{:type :bytes :path (format "META-INF/maven/%s/%s/pom.xml" (:group project) (:name project)) :bytes (.getBytes (pom/make-pom project))} {:type :bytes :path (scope "project.clj") :bytes (.getBytes (slurp (str (:root project) "/project.clj")))}] (for [doc (map (partial io/file (:root project)) (concat readmes licenses)) :when (.isFile doc)] {:type :bytes :path (scope (.getName doc)) :bytes (.getBytes (slurp doc))}) [{:type :path :path (:compile-path project)} {:type :paths :paths (:resource-paths project)}] (if-not (:omit-source project) [{:type :paths :paths (set (concat (:source-paths project) (:java-source-paths project)))}]) (:filespecs project)))) ;; Split out backwards-compatibility. Collapse into get-jar-filename for 3.0 (defn get-classified-jar-filename [project classifier] (let [target (doto (io/file (:target-path project)) utils/mkdirs) suffix (if classifier (str "-" (name classifier) ".jar") ".jar") name-kw (if (= classifier :standalone) :uberjar-name :jar-name) jar-name (or (project name-kw) (str (:name project) "-%s" suffix)) jar-name (format jar-name (:version project))] (str (io/file target jar-name)))) (defn- compile-main? [{:keys [main source-paths] :as project}] (and main (not (:skip-aot (meta main))) (some #(or (.exists (io/file % (b/path-for main "clj"))) (.exists (io/file % (b/path-for main "cljc")))) source-paths))) (def ^:private implicit-aot-warning (delay (main/info "Warning: specified :main without including it in :aot." "\nImplicit AOT of :main will be removed in Leiningen 3.0.0." "\nIf you only need AOT for your uberjar, consider adding" ":aot :all into your\n:uberjar profile instead."))) (defn warn-implicit-aot [orig-project] (let [project (project/merge-profiles orig-project [:uberjar])] (when (and (:main project) (not (:skip-aot (meta (:main project)))) (not= :all (:aot project)) (not= [:all] (:aot project)) (not (some #{(:main project)} (:aot project))) (not (some #(re-matches % (str (:main project))) (filter compile/regex? (:aot project))))) (force implicit-aot-warning)))) ;; TODO: remove for 3.0 (defn- add-main [project given-main] (warn-implicit-aot project) (let [project (if given-main (assoc project :main (symbol given-main)) project)] (if (and (compile-main? project) (not= :all (:aot project)) (not= [:all] (:aot project))) (update-in project [:aot] conj (:main project)) project))) (defn- process-project "Like update-in, but for preparing projects for (uber)jaring. f is a function that will take the old project and any supplied args and return the new project, but with whitelisted keys retained and with the main argument inserted if provided." [project main f & args] (-> (apply f project args) (project/retain-whitelisted-keys project) (add-main main))) (defn- preprocess-project [project & [main]] (process-project project main project/unmerge-profiles (project/non-leaky-profiles project))) (defn- get-jar-filename* [project uberjar?] (get-classified-jar-filename project (when uberjar? :standalone))) (defn get-jar-filename [project & [uberjar?]] (get-jar-filename* (preprocess-project project) uberjar?)) (defn build-jar "Build a jar for the given project and jar-file." [project jar-file] (eval/prep project) (write-jar project jar-file (filespecs project)) (main/info "Created" (str jar-file)) jar-file) (defn main-jar [project provided-profiles main] (let [project (process-project project main project/merge-profiles provided-profiles)] {[:extension "jar"] (build-jar project (get-jar-filename* project nil))})) (defn classifier-jar "Package up all the project's classified files into a jar file. Create a $PROJECT-$VERSION-$CLASSIFIER.jar file containing project's source files as well as .class files if applicable. The classifier is looked up in the project`s :classifiers map. If it's a map, it's merged like a profile. If it's a keyword, it's looked up in :profiles before being merged." [{:keys [target-path] :as project} provided-profiles classifier spec] (when (:dependencies spec) (main/warn "WARNING: Classifier specifies :dependencies which will be ignored.")) (let [profiles (concat provided-profiles [::target ::classifier]) target-profile {:target-path (.getPath (io/file target-path (name classifier)))} project (-> project (vary-meta assoc-in [:profiles ::classifier] spec) (vary-meta assoc-in [:profiles ::target] target-profile) (process-project nil project/merge-profiles profiles))] [[:classifier (name classifier) :extension "jar"] (build-jar project (get-classified-jar-filename project classifier))])) (defn classifier-jars "Package up all the project's classified files into jar files. Create a $PROJECT-$VERSION-$CLASSIFIER.jar file for each entry in the project's :classifiers. Returns a map of :classifier/:extension coordinates to files." [{:keys [classifiers] :as project} provided-profiles] (into {} (map #(apply classifier-jar project provided-profiles %) classifiers))) (defn jar "Package up all the project's files into a jar file. Create a $PROJECT-$VERSION.jar file containing project's source files as well as .class files if applicable. If project.clj contains a :main key, the -main function in that namespace will be used as the main-class for executable jar. With an argument, the jar will be built with an alternate main." ([project main] (utils/with-write-permissions (:root project) (when (:auto-clean project true) (clean/clean project)) (let [scoped-profiles (set (project/pom-scope-profiles project :provided)) default-profiles (set (project/expand-profile project :default)) provided-profiles (remove (set/difference default-profiles scoped-profiles) (-> project meta :included-profiles)) project (preprocess-project project main)] (merge (main-jar project provided-profiles main) (classifier-jars project provided-profiles))))) ([project] (jar project nil))) leiningen-2.9.1/src/leiningen/javac.clj000066400000000000000000000145301343535564500200300ustar00rootroot00000000000000(ns leiningen.javac "Compile Java source files." (:require [leiningen.classpath :as classpath] [leiningen.core.eval :as eval] [leiningen.core.main :as main] [leiningen.core.utils :as utils] [leiningen.core.project :as project] [clojure.java.io :as io] [clojure.string :as string]) (:import java.io.File)) (defn- stale-java-sources "Returns a lazy seq of file paths: every Java source file within dirs modified since it was most recently compiled into compile-path." [dirs compile-path] (for [dir dirs ^File source (filter #(-> ^File % (.getName) (.endsWith ".java")) (file-seq (io/file dir))) :let [rel-source (.substring (.getPath source) (inc (count dir))) rel-compiled (.replaceFirst rel-source "\\.java$" ".class") compiled (io/file compile-path rel-compiled)] :when (>= (.lastModified source) (.lastModified compiled))] (.getPath source))) (def ^:private special-ant-javac-keys "Legacy (Lein1/Ant task) javac options that do not translate to the new (JDK's javac) format as key-value pairs. For example, :debug \"off\" needs to be translated to -g:none." [:destdir :debug :debugLevel]) (defn- normalize-specials "Handles legacy (Lein1/Ant task) javac options that do not translate to the new (JDK's javac) format as key-value pairs." [{:keys [debug debugLevel]}] ;; debug "off" => -g:none ;; debugLevel "source,lines" => -g:source-lines (if (or (= "off" debug) (false? debug)) ["-g:none"] (if debugLevel [(str "-g:" debugLevel)] []))) (defn normalize-javac-options "Converts :javac-opts in Leiningen 1 format (passed as a map) into Leiningen 2 format (a vector). Options in Leiningen 2 format are returned unmodified." [opts] (if (map? opts) (let [special-opts (select-keys opts special-ant-javac-keys) other-opts (apply dissoc opts special-ant-javac-keys) specials (normalize-specials special-opts) others (mapcat (fn [[k v]] [(str "-" (name k)) v]) other-opts)] (vec (map (comp name str) (concat specials others)))) opts)) (defn- safe-quote [s] (str "\"" (string/replace s "\\" "\\\\") "\"")) ;; Tool's .run method expects the last argument to be an array of ;; strings, so that's what we'll return here. (defn- javac-options "Compile all sources of possible options and add important defaults. Result is a String java array of options." [project files args] (let [options-file (File/createTempFile ".leiningen-cmdline" nil)] (.deleteOnExit options-file) (with-open [options-file (io/writer options-file)] (doto options-file (.write (format "-cp %s\n" (safe-quote (classpath/get-classpath-string project)))) (.write (format "-d %s\n" (safe-quote (:compile-path project)))) (.write (string/join "\n" (map safe-quote files))))) (into-array String (concat (normalize-javac-options (:javac-options project)) args [(str "@" options-file)])))) ;; Pure java projects will not have Clojure on the classpath. As such, we need ;; to add it if it's not already there. (def subprocess-profile {:dependencies [^:displace ['org.clojure/clojure (clojure-version)]] :eval-in :subprocess}) (defn- subprocess-form "Creates a form for running javac in a subprocess." [compile-path files javac-opts] (main/debug "Running javac with" javac-opts) `(let [abort# (fn [& msg#] (.println java.lang.System/err (apply str msg#)) (java.lang.System/exit 1))] (if-let [compiler# (javax.tools.ToolProvider/getSystemJavaCompiler)] (do ~(when main/*info* `(binding [*out* *err*] (println "Compiling" ~(count files) "source files to" ~compile-path))) (.mkdirs (clojure.java.io/file ~compile-path)) (when-not (zero? (.run compiler# nil nil nil (into-array java.lang.String ~javac-opts))) (abort# "Compilation of Java sources(lein javac) failed."))) (abort# "Java compiler not found; Be sure to use java from a JDK\n" "rather than a JRE by modifying PATH or setting JAVA_CMD.")))) (defn javac-project-for-subprocess "Merge profiles to create project appropriate for javac subprocess. This function is mostly extracted to simplify testing, to validate that settings like `:local-repo` and `:mirrors` are respected." [project subprocess-profile] (-> (project/merge-profiles project [subprocess-profile]) (project/retain-whitelisted-keys project))) ;; We can't really control what is printed here. We're just going to ;; allow `.run` to attach in, out, and err to the standard streams. This ;; should have the effect of compile errors being printed. javac doesn't ;; actually output any compilation info unless it has to (for an error) ;; or you make it do so with `-verbose`. (defn- run-javac-subprocess "Run javac to compile all source files in the project. The compilation is run in a subprocess to avoid it from adding the leiningen standalone to the classpath, as leiningen adds itself to the classpath through the bootclasspath." [project args] (let [compile-path (:compile-path project) files (stale-java-sources (:java-source-paths project) compile-path) javac-opts (vec (javac-options project files args)) form (subprocess-form compile-path files javac-opts)] (when (seq files) (try (binding [eval/*pump-in* false] (eval/eval-in (javac-project-for-subprocess project subprocess-profile) form)) (catch Exception e (if-let [exit-code (:exit-code (ex-data e))] (main/exit exit-code) (throw e))))))) (defn javac "Compile Java source files. Add a :java-source-paths key to project.clj to specify where to find them. Options passed in on the command line as well as options from the :javac-options vector in project.clj will be given to the compiler; e.g. `lein javac -verbose`. Like the compile and deps tasks, this should be invoked automatically when needed and shouldn't ever need to be run by hand. By default it is called before compilation of Clojure source; change :prep-tasks to alter this." [project & args] (run-javac-subprocess project args)) leiningen-2.9.1/src/leiningen/new.clj000066400000000000000000000224351343535564500175400ustar00rootroot00000000000000(ns leiningen.new "Generate project scaffolding based on a template." (:refer-clojure :exclude [new list]) (:require [bultitude.core :as bultitude] [leiningen.core.classpath :as cp] [leiningen.core.project :as project] [leiningen.core.user :as user] [leiningen.core.main :refer [abort parse-options option-arg]] [leiningen.new.templates :refer [*dir* *force?*]]) (:import java.io.FileNotFoundException)) (def ^:dynamic *use-snapshots?* false) (def ^:dynamic *template-version* nil) (defn- fake-project [name] (let [template-symbol (symbol name "lein-template") template-version (cond *template-version* *template-version* *use-snapshots?* "(0.0.0,)" :else "RELEASE") user-profiles (:user (user/profiles)) repositories (reduce (:reduce (meta project/default-repositories)) project/default-repositories (:plugin-repositories user-profiles))] (merge {:templates [[template-symbol template-version]] :repositories repositories} (select-keys user-profiles [:mirrors])))) (defn resolve-remote-template [name sym] (try (cp/resolve-dependencies :templates (fake-project name) :add-classpath? true) (require sym) true (catch clojure.lang.Compiler$CompilerException e (abort (str "Could not load template, failed with: " (.getMessage e)))) (catch Exception e nil))) (defn resolve-template [name] (let [sym (symbol (str "leiningen.new." name))] (if (try (require sym) true (catch FileNotFoundException _ (resolve-remote-template name sym))) (resolve (symbol (str sym "/" name))) (abort "Could not find template" name "on the classpath.")))) ;; A lein-newnew template is actually just a function that generates files and ;; directories. We have a bit of convention: we expect that each template is on ;; the classpath and is based in a .clj file at `leiningen/new/`. Making this ;; assumption, users can simply give us the name of the template they wish to ;; use and we can `require` it without searching the classpath for it or doing ;; other time consuming things. If this namespace isn't found and we are ;; running Leiningen 2, we can resolve it via pomegranate first. ;; ;; Since our templates are just function calls just like Leiningen tasks, we can ;; also expect that a template generation function also be named the same as the ;; last segment of its namespace. This is what we call to generate the project. (defn create [template name & args] (cond (and (re-find #"(?i)(?`, we can easily search the classpath ;; to find templates in the same way that Leiningen can search to ;; find tasks. Furthermore, since our templates will always have a ;; function named after the template that is the entry-point, we can ;; also expect that it has the documentation for the template. We can ;; just look up these templates on the classpath, require them, and then ;; get the metadata off of that function to list the names and docs ;; for all of the available templates. (defn list [] (for [n (bultitude/namespaces-on-classpath :prefix "leiningen.new.") ;; There are things on the classpath at `leiningen.new` that we ;; don't care about here. We could use a regex here, but meh. :when (not= n 'leiningen.new.templates)] (-> (doto n require) (the-ns) (ns-resolve (symbol (last (.split (str n) "\\."))))))) (defn show "Show details for a given template." [name] (let [resolved (meta (resolve-template name))] (println (:doc resolved "No documentation available.")) (println) (println "Argument list:" (or (:help-arglists resolved) (:arglists resolved))))) (def ^{:dynamic true :doc "Bound to project map at runtime"} *project* nil) (defn- project-name-specified? [[first-arg & _]] (and first-arg (not (option-arg first-arg)))) (defn- template-specified? [[_ second-arg & _]] (and second-arg (not (option-arg second-arg)))) (defn- parse-args [[first-arg second-arg & opts :as args]] (if (project-name-specified? args) (let [template-name (if (template-specified? args) first-arg nil) new-project-name (if (template-specified? args) second-arg first-arg) options (parse-options (if (template-specified? args) opts (if second-arg (cons second-arg opts) opts)))] [template-name new-project-name options]) [nil nil (parse-options args)])) (defn- print-help [] (require 'leiningen.help) ((ns-resolve 'leiningen.help 'help) nil "new")) (defn ^{:no-project-needed true :help-arglists '[[project project-name] [project template project-name [-- & args]]] :subtasks (list)} new "Generate scaffolding for a new project based on a template. If only one argument is passed to the \"new\" task, the default template is used and the argument is used as the name of the project. If two arguments are passed, the first should be the name of a template, and the second is used as the name of the project, for example: lein new $TEMPLATE_NAME $PROJECT_NAME To generate to a directory different than your project's name use --to-dir: lein new $TEMPLATE_NAME $PROJECT_NAME --to-dir $DIR By default, the \"new\" task will not write to an existing directory. Supply the --force option to override this behavior: lein new $TEMPLATE_NAME $PROJECT_NAME --force lein new $TEMPLATE_NAME $PROJECT_NAME --to-dir $DIR --force Arguments can be passed to templates by adding them after \"new\"'s options. Use `--` to separate arguments to lein new and the actual template you are using: lein new $TEMPLATE_NAME $PROJECT_NAME --to-dir $DIR -- template-arg-1 template-arg-2 If you'd like to use an unreleased (ie, SNAPSHOT) template, pass in --snapshot: lein new $TEMPLATE_NAME $PROJECT_NAME --snapshot If you'd rather like to use a specific version of template, specify the version with --template-version option: lein new $TEMPLATE_NAME $PROJECT_NAME --template-version $TEMPLATE_VERSION If you use the `--snapshot` or `--template-version` argument with template args you may need to use `--` to prevent template args from being interpreted as arguments to `lein new`: lein new $TEMPLATE_NAME $PROJECT_NAME --snapshot -- template-arg-1 template-arg-2 Third-party templates can be found at https://clojars.org/search?q=lein-template. When creating a new project from a third-party template, use its group-id as the template name. Note that there's no need to \"install\" a given third- party template --- lein will automatically fetch it for you. Use `lein new :show $TEMPLATE` to see details about a given template. To create a new template of your own, see the documentation for the lein-new Leiningen plug-in." [project & args] (binding [*project* project] (let [[template-name new-project-name [options template-args]] (parse-args args)] (if (or (:--help options) (empty? args)) (print-help) (if-let [show-template (or (and (true? (:show options)) new-project-name) (:show options) (:--show options))] (show show-template) (binding [*dir* (or (:to-dir options) (:--to-dir options)) *use-snapshots?* (or (:snapshot options) (:--snapshot options)) *template-version* (or (:template-version options) (:--template-version options)) *force?* (or (:force options) (:--force options))] (apply create (or template-name "default") new-project-name template-args))))))) leiningen-2.9.1/src/leiningen/new/000077500000000000000000000000001343535564500170405ustar00rootroot00000000000000leiningen-2.9.1/src/leiningen/new/app.clj000066400000000000000000000024461343535564500203200ustar00rootroot00000000000000(ns leiningen.new.app "Generate a basic application project." (:require [leiningen.new.templates :refer [renderer year date project-name ->files sanitize-ns name-to-path multi-segment]] [leiningen.core.main :as main])) (defn app "An application project template." [name] (let [render (renderer "app") main-ns (multi-segment (sanitize-ns name)) data {:raw-name name :name (project-name name) :namespace main-ns :nested-dirs (name-to-path main-ns) :year (year) :date (date)}] (main/info "Generating a project called" name "based on the 'app' template.") (->files data ["project.clj" (render "project.clj" data)] ["README.md" (render "README.md" data)] ["doc/intro.md" (render "intro.md" data)] [".gitignore" (render "gitignore" data)] [".hgignore" (render "hgignore" data)] ["src/{{nested-dirs}}.clj" (render "core.clj" data)] ["test/{{nested-dirs}}_test.clj" (render "test.clj" data)] ["LICENSE" (render "LICENSE" data)] ["CHANGELOG.md" (render "CHANGELOG.md" data)] "resources"))) leiningen-2.9.1/src/leiningen/new/default.clj000066400000000000000000000030421343535564500211550ustar00rootroot00000000000000(ns leiningen.new.default "Generate a library project." (:require [leiningen.new.templates :refer [renderer year date project-name ->files sanitize-ns name-to-path multi-segment]] [leiningen.core.main :as main])) (defn default "A general project template for libraries. Accepts a group id in the project name: `lein new foo.bar/baz`" [name] (let [render (renderer "default") main-ns (multi-segment (sanitize-ns name)) data {:raw-name name :name (project-name name) :namespace main-ns :nested-dirs (name-to-path main-ns) :year (year) :date (date)}] (main/info "Generating a project called" name "based on the 'default' template.") (main/info "The default template is intended for library projects, not applications.") (main/info "To see other templates (app, plugin, etc), try `lein help new`.") (->files data ["project.clj" (render "project.clj" data)] ["README.md" (render "README.md" data)] ["doc/intro.md" (render "intro.md" data)] [".gitignore" (render "gitignore" data)] [".hgignore" (render "hgignore" data)] ["src/{{nested-dirs}}.clj" (render "core.clj" data)] ["test/{{nested-dirs}}_test.clj" (render "test.clj" data)] ["LICENSE" (render "LICENSE" data)] ["CHANGELOG.md" (render "CHANGELOG.md" data)] "resources"))) leiningen-2.9.1/src/leiningen/new/plugin.clj000066400000000000000000000020161343535564500210270ustar00rootroot00000000000000(ns leiningen.new.plugin (:require [leiningen.new.templates :refer [renderer sanitize year date ->files]] [leiningen.core.main :as main])) (defn plugin "A leiningen plugin project template." [^String name] (let [render (renderer "plugin") unprefixed (if (.startsWith name "lein-") (subs name 5) name) data {:name name :unprefixed-name unprefixed :sanitized (sanitize unprefixed) :year (year) :date (date)}] (main/info (str "Generating a fresh Leiningen plugin called " name ".")) (->files data ["project.clj" (render "project.clj" data)] ["README.md" (render "README.md" data)] [".gitignore" (render "gitignore" data)] [".hgignore" (render "hgignore" data)] ["src/leiningen/{{sanitized}}.clj" (render "name.clj" data)] ["LICENSE" (render "LICENSE" data)] ["CHANGELOG.md" (render "CHANGELOG.md" data)]))) leiningen-2.9.1/src/leiningen/new/template.clj000066400000000000000000000017451343535564500213540ustar00rootroot00000000000000(ns leiningen.new.template (:require [leiningen.new.templates :refer [renderer sanitize year date ->files]] [leiningen.core.main :as main])) (defn template "A meta-template for 'lein new' templates." [name] (let [render (renderer "template") data {:name name :sanitized (sanitize name) :placeholder "{{sanitized}}" :year (year) :date (date)}] (main/info "Generating fresh 'lein new' template project.") (->files data ["README.md" (render "README.md" data)] ["project.clj" (render "project.clj" data)] [".gitignore" (render "gitignore" data)] [".hgignore" (render "hgignore" data)] ["src/leiningen/new/{{sanitized}}.clj" (render "temp.clj" data)] ["resources/leiningen/new/{{sanitized}}/foo.clj" (render "foo.clj")] ["LICENSE" (render "LICENSE" data)] ["CHANGELOG.md" (render "CHANGELOG.md" data)]))) leiningen-2.9.1/src/leiningen/new/templates.clj000066400000000000000000000207571343535564500215430ustar00rootroot00000000000000;; You can write a 'new' task yourself without any extra plugins like ;; lein-newnew. What makes lein-new so useful is the `templates` task for ;; listing templates and this file. The primary problem with writing your ;; own project scaffolding tools that are domain-specific is you ;; generally have to reimplement the same things every single time. With ;; lein-new, you have this little library that your templates can use. ;; It has all the things a template is likely to need: ;; * an easy way to generate files and namespaces ;; * a way to render files written with a flexible template language ;; * a way to get those files off of the classpath transparently (ns leiningen.new.templates (:require [clojure.java.io :as io] [clojure.string :as string] [leiningen.core.eval :as eval] [leiningen.core.user :as user] [leiningen.core.utils :as utils] [leiningen.core.main :as main] [stencil.core :as stencil]) (:import (java.util Calendar))) (defn project-name "Returns project name from (possibly group-qualified) name: mygroup/myproj => myproj myproj => myproj" [s] (last (string/split s #"/"))) (defn fix-line-separators "Replace all \\n with system specific line separators." [s] (let [line-sep (if (user/getenv "LEIN_NEW_UNIX_NEWLINES") "\n" (user/getprop "line.separator"))] (string/replace s "\n" line-sep))) (defn slurp-to-lf "Returns the entire contents of the given reader as a single string. Converts all line endings to \\n." [r] (let [sb (StringBuilder.)] (loop [s (.readLine r)] (if (nil? s) (str sb) (do (.append sb s) (.append sb "\n") (recur (.readLine r))))))) (defn slurp-resource "Reads the contents of a resource. Temporarily converts line endings in the resource to \\n before converting them into system specific line separators using fix-line-separators." [resource] (if (string? resource) ; for 2.0.0 compatibility, can break in 3.0.0 (-> resource io/resource io/reader slurp-to-lf fix-line-separators) (-> resource io/reader slurp-to-lf fix-line-separators))) (defn sanitize "Replace hyphens with underscores." [s] (string/replace s "-" "_")) (defn multi-segment "Make a namespace multi-segmented by adding another segment if necessary. The additional segment defaults to \"core\"." ([s] (multi-segment s "core")) ([s final-segment] (if (.contains s ".") s (format "%s.%s" s final-segment)))) (defn name-to-path "Constructs directory structure from fully qualified artifact name: \"foo-bar.baz\" becomes \"foo_bar/baz\" and so on. Uses platform-specific file separators." [s] (-> s sanitize (string/replace "." java.io.File/separator))) (defn sanitize-ns "Returns project namespace name from (possibly group-qualified) project name: mygroup/myproj => mygroup.myproj myproj => myproj mygroup/my_proj => mygroup.my-proj" [s] (-> s (string/replace "/" ".") (string/replace "_" "-"))) (defn group-name "Returns group name from (a possibly unqualified) name: my.long.group/myproj => my.long.group mygroup/myproj => mygroup myproj => nil" [s] (let [grpseq (butlast (string/split (sanitize-ns s) #"\."))] (if (seq grpseq) (->> grpseq (interpose ".") (apply str))))) (defn year "Get the current year. Useful for setting copyright years and such." [] (.get (Calendar/getInstance) Calendar/YEAR)) (defn date "Get the current date as a string in ISO8601 format." [] (let [df (java.text.SimpleDateFormat. "yyyy-MM-dd")] (.format df (java.util.Date.)))) ;; It'd be silly to expect people to pull in stencil just to render a mustache ;; string. We can just provide this function instead. In doing so, it is much ;; less likely that template authors will have to pull in any external ;; libraries. Though they are welcome to if they need. (def render-text stencil/render-string) ;; Templates are expected to store their mustache template files in ;; `leiningen/new/