diff --git a/.circleci/config.yml b/.circleci/config.yml index af09de34a..4f464649e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,55 +1,68 @@ -version: 2.1 - -executors: - clojure: - docker: - - image: clojure:<< parameters.java_version >>-lein - parameters: - java_version: - description: "Java version" - default: "openjdk-11" - type: string - working_directory: ~/leiningen - -jobs: - build: - executor: clojure - parameters: - java_version: - description: "Java version" - default: << parameters.java_version >> - type: string - steps: - - checkout - - restore_cache: - key: leiningen-{{ checksum "project.clj" }} - - run: apt update -qq && apt install -y gnupg - - run: - name: Bootstrap leiningen-core - working_directory: ~/leiningen/leiningen-core - command: lein bootstrap - - run: - name: Test Leiningen - command: bin/lein test - - run: - name: Test lein-pprint - working_directory: lein-pprint - command: lein test - - save_cache: - paths: - - $HOME/.m2 - - $HOME/.lein - key: leiningen-{{ checksum "project.clj" }} - -workflows: - test-with-matrix: - jobs: - - build: - name: "openjdk8" - java_version: "openjdk-8" - - build: - name: "openjdk11" - java_version: "openjdk-11" - - build: - name: "openjdk16" - java_version: "openjdk-16" +# -*- js -*- +{ + "version": 2.1, + "executors": { + "clojure": { + "docker": [{"image": "clojure:<< parameters.java_version >>-lein"}], + "parameters": { + "java_version": { + "description": "Java version", + "default": "openjdk-17", + "type": "string" + } + }, + "working_directory": "~/leiningen" + } + }, + "jobs": { + "build": { + "executor": "clojure", + "parameters": { + "java_version": { + "description": "Java version", + "default": "<< parameters.java_version >>", + "type": "string" + } + }, + "steps": [ + "checkout", + { + "run": "apt update -qq && apt install -y gnupg openssh-client" + }, + { + "restore_cache": { + "key": "leiningen-{{ checksum \"project.clj\" }}-{{ checksum \"leiningen-core/project.clj\" }}" + } + }, + { + "run": { + "name": "Bootstrap leiningen-core", + "working_directory": "~/leiningen/leiningen-core", + "command": "lein bootstrap" + } + }, + { + "run": { + "name": "Test Leiningen", + "command": "bin/lein test" + } + }, + { + "save_cache": { + "paths": ["~/.m2/repository"], + "key": "leiningen-{{ checksum \"project.clj\" }}-{{ checksum \"leiningen-core/project.clj\" }}" + } + } + ] + } + }, + "workflows": { + "test-with-matrix": { + "jobs": [ + {"build": {"name": "openjdk8", "java_version": "openjdk-8"}}, + {"build": {"name": "openjdk17", "java_version": "openjdk-17"}}, + {"build": {"name": "openjdk21", "java_version": "openjdk-21"}} + ] + } + } +} diff --git a/.gitignore b/.gitignore index 76d909ab6..1f885a8d8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,11 @@ test_projects/*/target pom.xml deps.txt profiles.clj +/test/.gnupg/crls.d/DIR.txt +/test_projects/sample/project.clj.sig +/web/deploy.html +/web/faq.html +/web/plugins.html +/web/profiles.html +/web/templates.html +/web/tutorial.html diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 000000000..1a75dd706 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,10 @@ +# -*- js -*- +{"steps": + {"build": + {"image": "debian:stable-slim", + "commands": [ + "apt-get update -qq", + "apt-get install -y gnupg leiningen openssh-client", + "cd leiningen-core && lein bootstrap", + "cd .. && bin/lein test"], + "when": [{"event": "push"}]}}} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d74596a06..f47f50fd7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,39 @@ # 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. +Leiningen is the most widely-contributed-to Clojure project a the time +of this writing. We welcome potential contributors and do our best to +try to make it easy to help out. -Discussion occurs primarily in the #leiningen channel on Libera chat. +Discussion occurs primarily in the #leiningen channel on [Libera +chat](https://libera.chat). Please report issues on the -[GitHub issue tracker](https://github.com/technomancy/leiningen/issues). - -Code submissions should -be sent 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). +[issue tracker](https://codeberg.org/leiningen/leiningen/issues). Issues used +to be reported in the [GitHub tracker](https://github.com/technomancy/leiningen/issues) +so you may want to check there to see if things have already been reported. + +Code submissions should be sent as [pull +requests](https://codeberg.org/leiningen/leiningen/pulls). Please +use topic branches when sending pull requests rather than committing +directly to `main` in order to minimize unnecessary merge commit +clutter. Direct pull requests towards the `main` branch, not the +stable branch. + +You can add a 1-line summary of your change to `NEWS.md` if it's a +user-visible issue that affects more than a handful of people. + +Please note that it is ethically unacceptable to submit patches (to +this project or any other) which you did not author yourself without +giving clear attribution to the original author. Note that this +includes submitting changes generated by most so-called "artificial +intelligence" language models as these systems often make it +impossible to even identify (much less credit) the original author. + +Note: the canonical repository for Leiningen is [on +Codeberg](https://codeberg.org/leiningen/leiningen) but we maintain [a +mirror on GitHub](https://github.com/technomancy/leiningen) for the +time being in order to ease the transition. Please update your links +and git remotes. ## Codebase @@ -26,7 +43,7 @@ top-level project. The underlying mechanisms for things like 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) +[readme for the leiningen-core library](https://codeberg.org/leiningen/leiningen/src/main/leiningen-core/README.md) and `doc/PLUGINS.md` for more details on how Leiningen's codebase is structured. @@ -63,33 +80,43 @@ 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 +Using `bin/lein` alone from the main 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 +You can also bootstrap using [Maven](https://maven.apache.org/) to work +around the chicken/egg bootstrapping problem if you cannot or do not want to +install a stable Leiningen build. + +```bash +$ cd leiningen-core +$ mvn install +$ mvn dependency:build-classpath -Dmdep.outputFile=cp.txt +``` + +### Uberjar from main 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: +enhancement, you can build an uberjar from main 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 +$ cp bin/lein $HOME/bin/lein-main ``` 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 +Note that changes on main 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 +Before you submit 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 diff --git a/COPYING b/COPYING index 00aacb5e0..c1f030fb3 100644 --- a/COPYING +++ b/COPYING @@ -272,7 +272,7 @@ TERMS AND CONDITIONS. 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 + listed at https://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 diff --git a/NEWS.md b/NEWS.md index 88148faf1..555991cf4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,12 +1,57 @@ # Leiningen News -- history of user-visible changes -## 2.9.9 / ??? +## 2.11.3 / ??? +* Add `:plugin-tree-data` subcommand to deps task. (Gabriel Giussi) + +## 2.11.2 / 2024-02-13 + +* Add `:preserve-eval-meta` setting to avoid project code reflection. (Marco Biscaro) +* Fix a bug where metadata on project code caused plugin incompatibilities. (Marco Biscaro) + +## 2.11.1 / 2024-01-28 + +* Fix a bug when deploying using passwords read from the console. (Phil Hagelberg) + +## 2.11.0 / 2024-01-27 + +* Top-level `:exclusions` can now affect top-level `:dependencies`. (Juan Monetta) +* Fix a bug where `:eval-in :nrepl` couldn't detect running repl. (Phil Hagelberg) +* Fix a bug where `:eval-in :nrepl` would crash. (Marco Biscaro) +* Fix a bug where files on test path could be visible during jar. (Phil Hagelberg) +* Fix an issue with `check` in namespaces that rely on AOT. (Phil Hagelberg) +* Fix a redundant confusing dependencies warning. (Phil Hagelberg) +* Add `static-classpath` task for static analysis. (Phil Hagelberg) +* Major performance improvements handling pathological dependency trees. (Marco Biscaro) +* Improve error reporting for search failures. (rome user) +* Support XDG config directories. (Phil Hagelberg) +* Use `$XDG_CACHE_HOME` for self-installs if it exists. (Phil Hagelberg) +* Add warnings for buggy composite profiles. (Phil Hagelberg) + +## 2.10.0 / 2022-12-09 + +* Update to nREPL 1.0.0 (Phil Hagelberg) +* Fix a bug where `:eval-in :leiningen` could suppress test exit code. (Phil Hagelberg) +* Add the ability to sign deployed files using SSH keys, not just GPG. (Phil Hagelberg) +* Fix a bug where uberjar splices profiles into target path incorrectly. (Phil Hagelberg) + +## 2.9.10 / 2022-08-09 + +* Fix a bug where dev-resources could leak into jars/uberjars. (Phil Hagelberg) +* Avoid illegal reflective access doing XML parsing in uberjar/search. (Phil Hagelberg) + +## 2.9.9 / 2022-08-05 + +* Migrate the repository from Github to Codeberg. (Phil Hagelberg) +* Fix a bug in `new` where template group-ids could be ignored. (Phil Hagelberg) +* Work around a change in Java 9 which broke template listing. (Phil Hagelberg) +* Fix a bug in pedantic checks which resulted in infinite loops. (Phil Hagelberg) * Prevent `module-info.class` files from being included in uberjars. (Phil Hagelberg) * Prevent duplicate warnings in `resource-paths` when creating jars. (Phil Hagelberg) * Fix an issue with `check` where AOT would shadow reflection warnings. (Phil Hagelberg) * Allow `change` to edit dependency versions. (Eric Schoen) * Fix a bug where composite profiles would leak dependencies downstream. (Phil Hagelberg) +* Allow `repl` to bind to filesystem sockets via `:headless :socket PATH` (Rob Browning) ## 2.9.8 / 2021-11-11 @@ -741,7 +786,7 @@ * 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. + See https://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) diff --git a/README.md b/README.md index 48e1f575b..4c33e1b8b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Leiningen -[![CircleCI](https://circleci.com/gh/technomancy/leiningen.svg?style=svg)](https://circleci.com/gh/technomancy/leiningen) +[![status-badge](https://ci.codeberg.org/api/badges/leiningen/leiningen/status.svg)](https://ci.codeberg.org/leiningen/leiningen) Leiningen logo @@ -13,31 +13,36 @@ Leiningen is for automating Clojure projects without setting your hair on fire. +Note: the canonical repository for Leiningen is [on +Codeberg](https://codeberg.org/leiningen/leiningen) but we maintain [a +mirror on GitHub](https://github.com/technomancy/leiningen) for the +time being in order to ease the transition. Please update your links +and git remotes. + ## 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. +If your preferred [package manager](https://wiki.leiningen.org/Packaging) +offers a recent version of Leiningen, try that first. 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`) +1. Make sure you have Java installed; [OpenJDK](https://adoptium.net) is recommended +2. [Download the `lein` script from the `stable` branch](https://codeberg.org/leiningen/leiningen/raw/branch/stable/bin/lein) + of this project +3. Place it on your `$PATH` (`/usr/local/bin` for example) +4. Set it to be executable. (`sudo chmod +x /usr/local/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) +[the batch file](https://codeberg.org/leiningen/leiningen/raw/branch/stable/bin/lein.bat) or +[PowerShell version](https://codeberg.org/leiningen/leiningen/raw/branch/stable/bin/lein.ps1) instead. ## Basic Usage The -[tutorial](https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md) +[tutorial](https://codeberg.org/leiningen/leiningen/src/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: @@ -73,19 +78,19 @@ The `project.clj` file in the project root should look like this: (defproject myproject "0.5.0-SNAPSHOT" :description "A project for doing things." :license "Eclipse Public License 1.0" - :url "http://github.com/technomancy/myproject" + :url "https://codelab.org/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) +[sample.project.clj](https://codeberg.org/leiningen/leiningen/src/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). +[profiles](https://codeberg.org/leiningen/leiningen/src/stable/doc/PROFILES.md). ## Documentation @@ -93,38 +98,38 @@ 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) + * [Tutorial](https://codeberg.org/leiningen/leiningen/src/stable/doc/TUTORIAL.md) (start here if you are new) + * [FAQ](https://codeberg.org/leiningen/leiningen/src/stable/doc/FAQ.md) + * [Profiles](https://codeberg.org/leiningen/leiningen/src/stable/doc/PROFILES.md) + * [Deployment & Distribution of Libraries](https://codeberg.org/leiningen/leiningen/src/stable/doc/DEPLOY.md) + * [Sample project.clj](https://codeberg.org/leiningen/leiningen/src/stable/sample.project.clj) + * [Polyglot (e.g. Clojure/Java) projects](https://codeberg.org/leiningen/leiningen/src/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) +* [Writing Plugins](https://codeberg.org/leiningen/leiningen/src/stable/doc/PLUGINS.md) +* [Writing Templates](https://codeberg.org/leiningen/leiningen/src/stable/doc/TEMPLATES.md) +* [Contributing](https://codeberg.org/leiningen/leiningen/src/stable/CONTRIBUTING.md) +* [Building Leiningen](https://codeberg.org/leiningen/leiningen/src/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) +[the plugins wiki page](https://wiki.leiningen.org/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) +[profiles guide](https://codeberg.org/leiningen/leiningen/src/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) +[plugin guide](https://codeberg.org/leiningen/leiningen/src/stable/doc/PLUGINS.md) explains how to write plugins. ## License -Source Copyright © 2009-2021 Phil Hagelberg, Alex Osborne, Dan Larkin, and -[contributors](https://github.com/technomancy/leiningen/contributors). +Source Copyright © 2009-2022 Phil Hagelberg, Alex Osborne, Dan Larkin, and +contributors. Distributed under the Eclipse Public License, the same as Clojure uses. See the file COPYING. diff --git a/bin/lein b/bin/lein index a24bce5a7..b883b7b02 100755 --- a/bin/lein +++ b/bin/lein @@ -4,13 +4,9 @@ # 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.9-SNAPSHOT" +export LEIN_VERSION="2.11.3-SNAPSHOT" # Must be sha256sum, will be replaced by bin/release -export LEIN_CHECKSUM='2a0e9114e0d623c748a9ade5d72b54128b31b5ddb13f51b04c533f104bb0c48d' +export LEIN_CHECKSUM='7d31ae23ae769e927438b0cd55d15a93e7dabab09fd4fc15877979161e108774' case $LEIN_VERSION in *SNAPSHOT) SNAPSHOT="YES" ;; @@ -36,6 +32,10 @@ else cygwin=false fi +function msg { + echo "$@" 1>&2 +} + function command_not_found { msg "Leiningen couldn't find $1 in your \$PATH ($PATH), which is required." exit 1 @@ -119,87 +119,7 @@ function self_install { 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_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-"-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 - -# This needs to be defined before we call SHASUM_CMD below -if [ "$SHASUM_CMD" = "" ]; then - if type -p sha256sum >/dev/null 2>&1; then - export SHASUM_CMD="sha256sum" - elif type -p shasum >/dev/null 2>&1; then - export SHASUM_CMD="shasum --algorithm 256" - elif type -p sha256 >/dev/null 2>&1; then - export SHASUM_CMD="sha256 -q" - else - command_not_found sha256sum - 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 +function run_from_source() { LEIN_DIR="$(cd $(dirname "$BIN_DIR");pwd -P)" # Need to use lein release to bootstrap the leiningen-core library (for aether) @@ -242,52 +162,17 @@ if [ -r "$BIN_DIR/../src/leiningen/version.clj" ]; then else add_path CLASSPATH "$(cat "$LEIN_DIR/leiningen-core/.lein-bootstrap" 2> /dev/null)" fi -else # Not running from a checkout +} + +function run_from_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 +function cmd_self_install() { if [ -r "$BIN_DIR/../src/leiningen/version.clj" ]; then cat <<-'EOS' 1>&2 Running self-install from a checkout is not supported. @@ -297,7 +182,9 @@ if [ "$1" = "self-install" ]; then fi msg "Manual self-install is deprecated; it will run automatically when necessary." self_install -elif [ "$1" = "upgrade" ] || [ "$1" = "downgrade" ]; then +} + +function cmd_up_downgrade() { if [ "$LEIN_DIR" != "" ]; then msg "The upgrade task is not meant to be run from a checkout." exit 1 @@ -347,7 +234,9 @@ elif [ "$1" = "upgrade" ] || [ "$1" = "downgrade" ]; then exit 1;; esac fi -else +} + +function cmd_run { if $cygwin; then # When running on Cygwin, use Windows-style paths for java ORIGINAL_PWD=$(cygpath -w "$ORIGINAL_PWD") @@ -396,7 +285,6 @@ else "$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" \ @@ -424,4 +312,146 @@ else exit $EXIT_CODE fi fi +} + +# 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 + +# User init +if [ "$LEIN_HOME" = "" ]; then + # Prefer the old location if present + if [ -d "$HOME/.lein" ]; then + export LEIN_HOME="$HOME/.lein" + elif [ -d "$XDG_CACHE_HOME/leiningen" ]; then + export LEIN_HOME="$XDG_CACHE_HOME/leiningen" + else + export LEIN_HOME="$HOME/.lein" + fi +fi + +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 -m "$LEIN_HOME") +fi + +# 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")" + + +LEIN_JAR="${LEIN_JAR:-${LEIN_HOME}/self-installs/leiningen-${LEIN_VERSION}-standalone.jar}" + +export LEIN_JVM_OPTS="${LEIN_JVM_OPTS-"-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 + +# This needs to be defined before we call SHASUM_CMD below +if [ "$SHASUM_CMD" = "" ]; then + if type -p sha256sum >/dev/null 2>&1; then + export SHASUM_CMD="sha256sum" + elif type -p shasum >/dev/null 2>&1; then + export SHASUM_CMD="shasum --algorithm 256" + elif type -p sha256 >/dev/null 2>&1; then + export SHASUM_CMD="sha256 -q" + else + command_not_found sha256sum + 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 + run_from_source "$1" +else + run_from_checkout "$1" + + 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/2.11.3-SNAPSHOT6/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 + cmd_self_install +elif [ "$1" = "upgrade" ] || [ "$1" = "downgrade" ]; then + cmd_up_downgrade "$@" +else + cmd_run "$@" fi diff --git a/bin/lein-pkg b/bin/lein-pkg index fc298c746..55cb20c33 100644 --- a/bin/lein-pkg +++ b/bin/lein-pkg @@ -1,15 +1,156 @@ -#!/bin/bash +#!/usr/bin/env 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.9-SNAPSHOT" +export LEIN_VERSION="2.11.3-SNAPSHOT" + +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 msg { + echo "$@" 1>&2 +} + +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/dev/null; then + # Check if mktemp is available before using it + TRAMPOLINE_FILE="$(mktemp -t 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 \ + $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 +} # cd to the project root, if applicable NOT_FOUND=1 ORIGINAL_PWD="$PWD" -while [ ! -r "$PWD/project.clj" ] && [ "$PWD" != "/" ] && [ $NOT_FOUND -ne 0 ]; do +while [ ! -r "$PWD/project.clj" ] && [ "$PWD" != "/" ] && [ $NOT_FOUND -ne 0 ] +do cd .. if [ "$(dirname "$PWD")" = "/" ]; then NOT_FOUND=0 @@ -17,91 +158,96 @@ while [ ! -r "$PWD/project.clj" ] && [ "$PWD" != "/" ] && [ $NOT_FOUND -ne 0 ]; 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 + if [ -e "$f" ]; then + source "$f" + fi done -export LEIN_JVM_OPTS="${LEIN_JVM_OPTS-"-XX:+TieredCompilation -XX:TieredStopAtLevel=1"}" +if $cygwin; then + export LEIN_HOME=$(cygpath -w "$LEIN_HOME") +fi -grep -E -q '^\s*:eval-in\s+:classloader\s*$' project.clj 2> /dev/null && -LEIN_JVM_OPTS="${LEIN_JVM_OPTS:-'-Xms64m -Xmx512m'}" +# 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")" # 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" +export LEIN_JVM_OPTS="${LEIN_JVM_OPTS-"-XX:+TieredCompilation -XX:TieredStopAtLevel=1"}" + +# This needs to be defined before we call SHASUM_CMD below +if [ "$SHASUM_CMD" = "" ]; then + if type -p sha256sum >/dev/null 2>&1; then + export SHASUM_CMD="sha256sum" + elif type -p shasum >/dev/null 2>&1; then + export SHASUM_CMD="shasum --algorithm 256" + elif type -p sha256 >/dev/null 2>&1; then + export SHASUM_CMD="sha256 -q" + else + command_not_found sha256sum fi fi -# apply context specific CLASSPATH entries -if [ -f .lein-classpath ]; then - CLASSPATH="$(cat .lein-classpath):$CLASSPATH" -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 [ -n "$DEBUG" ]; then - echo "Leiningen's classpath: $CLASSPATH" -fi +run_from_checkout "$1" -# Which Java? +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 JAVA_CMD="${JAVA_CMD:-"java"}" -export LEIN_JAVA_CMD="${LEIN_JAVA_CMD:-$JAVA_CMD}" +export LEIN_JAVA_CMD="${LEIN_JAVA_CMD:-${JAVA_CMD:-java}}" -if [[ "$(basename "$LEIN_JAVA_CMD")" == *drip* ]]; then +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"}" -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' +# 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 [ "$LEIN_FAST_TRAMPOLINE" != "" ] && [ -r project.clj ]; then - INPUTS="$* $(cat project.clj) $LEIN_VERSION $(test -f "$LEIN_HOME/profiles.clj" && cat "$LEIN_HOME/profiles.clj") $(test -f profiles.clj && cat 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 +if $cygterm; then + LEIN_JVM_OPTS="$LEIN_JVM_OPTS -Djline.terminal=jline.UnixTerminal" + stty -icanon min 1 -echo > /dev/null 2>&1 fi if [ "$1" = "upgrade" ]; then @@ -111,37 +257,4 @@ if [ "$1" = "upgrade" ]; then 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 +cmd_run "$@" diff --git a/bin/lein.bat b/bin/lein.bat index d05c2aaca..0d577fe73 100755 --- a/bin/lein.bat +++ b/bin/lein.bat @@ -2,7 +2,7 @@ setLocal EnableExtensions EnableDelayedExpansion -set LEIN_VERSION=2.9.9-SNAPSHOT +set LEIN_VERSION=2.11.3-SNAPSHOT if "%LEIN_VERSION:~-9%" == "-SNAPSHOT" ( set SNAPSHOT=YES diff --git a/bin/lein.ps1 b/bin/lein.ps1 index 1b2635b8b..7af3abcfb 100644 --- a/bin/lein.ps1 +++ b/bin/lein.ps1 @@ -34,7 +34,7 @@ function Set-ParentLocation([string]$file) function Initialize-Environment { - $env:LEIN_VERSION = '2.9.9-SNAPSHOT' + $env:LEIN_VERSION = '2.11.3-SNAPSHOT' $env:SNAPSHOT = if($env:LEIN_VERSION -like '*-SNAPSHOT'){'YES'}else{'NO'} #TODO: Still needed? $env:ORIGINAL_PWD = $PWD -replace '\\$','\\' Set-ParentLocation project.clj diff --git a/bin/release b/bin/release index 5d918eac8..4cd3b2cc7 100755 --- a/bin/release +++ b/bin/release @@ -1,21 +1,26 @@ #!/bin/bash -set -e -u - if [ "$1" = "" ]; then echo "usage: $0 VERSION" exit 1 fi +set -e -u + RELEASE_VERSION=$1 CURRENT_VERSION="$RELEASE_VERSION-SNAPSHOT" +LEIN_STABLE=$2 + +if [ "$LEIN_STABLE" = "" ]; then + LEIN_STABLE=lein-stable +fi # 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." +if [ ! -x `which $LEIN_STABLE` ]; then + echo "Install a stable version of Leiningen as $LEIN_STABLE." exit 1 fi @@ -34,7 +39,7 @@ LEIN_ROOT=$PWD echo "Bootstrapping..." cd leiningen-core -lein-stable do clean, bootstrap +$LEIN_STABLE do clean, bootstrap cd .. echo "Generating uberjar..." @@ -43,6 +48,7 @@ bin/lein uberjar RELEASE_JAR=$PWD/target/leiningen-$RELEASE_VERSION-standalone.jar RELEASE_JAR_CHECKSUM="$(sha256sum $RELEASE_JAR | awk '{ print $1 }')" SELF_INSTALL_JAR=$HOME/.lein/self-installs/$(basename $RELEASE_JAR) +mkdir -p $HOME/.lein/self-installs cp $RELEASE_JAR $SELF_INSTALL_JAR sed -i "s/export LEIN_CHECKSUM=.*/export LEIN_CHECKSUM='$RELEASE_JAR_CHECKSUM'/" bin/lein @@ -62,7 +68,7 @@ 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 "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 @@ -78,14 +84,18 @@ 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 +git push && git push --tags && git push origin main:stable -echo "Upload $SELF_INSTALL_JAR and $SELF_INSTALL_JAR.asc to GitHub:" +echo "Upload to Codeberg and Github:" +echo " $SELF_INSTALL_JAR" +echo " $SELF_INSTALL_JAR.asc" +echo +echo "https://codeberg.org/leiningen/leiningen/releases/new?tag=$RELEASE_VERSION" echo "https://github.com/technomancy/leiningen/releases/new?tag=$RELEASE_VERSION" -echo "Copy this version's section of NEWS.md to the GitHub release description." +echo "Copy this version's section of NEWS.md to the 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 " lein deploy clojars && cd leiningen-core && lein deploy clojars" echo "" -echo "Then run: bin/bump $RELEASE_VERSION NEXT_VERSION" +echo "Then run: bin/bump $RELEASE_VERSION NEXT_VERSION-SNAPSHOT" diff --git a/doc/BEGINNER_MISTAKES.md b/doc/BEGINNER_MISTAKES.md new file mode 100644 index 000000000..0e4144b79 --- /dev/null +++ b/doc/BEGINNER_MISTAKES.md @@ -0,0 +1,25 @@ + + +**Table of Contents** + +- [BEGINNER_MISTAKES](#beginner_mistakes) + + + +# Beginner Mistakes + +**Q:** When I have no `project.clj` the command `lein repl` works, but I + added one and now `lein repl` crashes with: +``` +Error: Could not find or load main class clojure.main +Caused by: java.lang.ClassNotFoundException: clojure.main +Subprocess failed (exit code: 1) +``` +**A:** When you don't have a `project.clj` Leiningen automatically includes + the core Clojure language for you. When you add a `project.clj`, + Leiningen expects you to specify which version of Clojure you'll + use. If you're just experimenting with Clojure, remove `project.clj`. + Otherwise, make sure your `project.clj` has a `:dependencies` section + with at least `[org.clojure/clojure "1.11.1"]` in it. (Change the version + from `1.11.1` as necessary.) + diff --git a/doc/DEPLOY.md b/doc/DEPLOY.md index 44f8f23c1..7b0c2c800 100644 --- a/doc/DEPLOY.md +++ b/doc/DEPLOY.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [Deploying Libraries](#deploying-libraries) - [Private Repositories](#private-repositories) @@ -25,7 +25,7 @@ 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). +[the Leiningen tutorial](https://codeberg.org/leiningen/leiningen/src/stable/doc/TUTORIAL.md). However, deploying elsewhere is not always that straightforward. ## Private Repositories @@ -77,7 +77,7 @@ you can deploy to S3 buckets using the 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 +[Nexus](https://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 @@ -137,7 +137,7 @@ 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 guide](https://codeberg.org/leiningen/leiningen/src/stable/doc/GPG.md). ### GPG @@ -249,6 +249,22 @@ your `project.clj`: You can use this to alias any `:repositories` entry; Clojars is just the most common use case. +## Signing Artifacts + +By default Leiningen will attempt to sign all artifacts that are deployed +using GPG. If you prefer, you can [sign them using +SSH](https://www.agwa.name/blog/post/ssh_signatures) instead. If you don't +already use GPG, this may be more convenient for you. Edit your +`~/.lein/profiles.clj` file to add a `:user` profile with a `:signing` map: + +```clj +{:user {:signing {:gpg-key false + :ssh-key "~/.ssh/id_rsa"}}} +``` + +If you want to keep signing with both SSH and GPG at the same time, you can +omit the `:gpg-key false` setting. + ## Releasing Simplified Once you have your repositories and user credentials configured for deploying, @@ -346,7 +362,7 @@ 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 +By default `["vcs" "tag"]` will create a 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"]`. diff --git a/doc/FAQ.md b/doc/FAQ.md index fbfbb25f3..6d8179558 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [FAQ](#faq) @@ -13,11 +13,11 @@ **Q:** What's a group ID? How do snapshots work? **A:** See the - [tutorial](https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md) + [tutorial](https://codeberg.org/leiningen/leiningen/src/stable/doc/TUTORIAL.md) for background. **Q:** How should I pick my version numbers? -**A:** Use [semantic versioning](http://semver.org) to communicate +**A:** Use [semantic versioning](https://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 @@ -25,7 +25,7 @@ **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) + [deploy guide](https://codeberg.org/leiningen/leiningen/src/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 @@ -38,7 +38,7 @@ **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) + [tutorial](https://codeberg.org/leiningen/leiningen/src/stable/doc/TUTORIAL.md) to learn more. **Q:** Is it possible to exclude indirect dependencies? @@ -119,7 +119,7 @@ **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). + [ways to improve startup time](https://wiki.leiningen.org/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 @@ -239,7 +239,7 @@ 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) +**A:** You probably downloaded `lein`/`lein.bat` from the [main branch](https://codeberg.org/leiningen/leiningen/src/main/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 diff --git a/doc/GPG.md b/doc/GPG.md index 8f432b913..8cb393d48 100644 --- a/doc/GPG.md +++ b/doc/GPG.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [Using GPG](#using-gpg) - [What is it?](#what-is-it) @@ -183,7 +183,7 @@ 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 +[deploy guide](https://codeberg.org/leiningen/leiningen/src/stable/doc/DEPLOY.md). Once you are configured to sign releases, signing tags should be straightforward. diff --git a/doc/MIXED_PROJECTS.md b/doc/MIXED_PROJECTS.md index 53a0ae5a7..8cb0c85aa 100644 --- a/doc/MIXED_PROJECTS.md +++ b/doc/MIXED_PROJECTS.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [Polyglot (Clojure, Java) Projects With Leiningen](#polyglot-clojure-java-projects-with-leiningen) - [Source Layout](#source-layout) diff --git a/doc/PLUGINS.md b/doc/PLUGINS.md index c6b9979bc..dc1414fdf 100644 --- a/doc/PLUGINS.md +++ b/doc/PLUGINS.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [Leiningen Plugins](#leiningen-plugins) - [Writing a Plugin](#writing-a-plugin) @@ -76,7 +76,8 @@ 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), +making a plugin might be the right choice if one doesn't +[exist already](https://wiki.leiningen.org/Plugins). ## Writing a Plugin @@ -87,11 +88,11 @@ 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) +[all of Leiningen's own dependencies](https://codeberg.org/leiningen/leiningen/src/stable/project.clj) will be available. See the `lein-pprint` directory -[in the Leiningen source](https://github.com/technomancy/leiningen/tree/stable/lein-pprint) +[in the Leiningen source](https://codeberg.org/leiningen/leiningen/src/stable/lein-pprint) for a sample of a very simple plugin. When emitting output, please use `leiningen.core.main/info`, @@ -542,7 +543,7 @@ 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), +[existing plugins](https://wiki.leiningen.org/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 @@ -569,7 +570,7 @@ 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. +wiki](https://wiki.leiningen.org/Plugins) once it's ready. Hopefully the plugin mechanism is simple and flexible enough to let you bend Leiningen to your will. diff --git a/doc/PROFILES.md b/doc/PROFILES.md index bef12a2a6..7b2586a49 100644 --- a/doc/PROFILES.md +++ b/doc/PROFILES.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [Profiles](#profiles) - [Declaring Profiles](#declaring-profiles) @@ -201,12 +201,12 @@ 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 `+`: +defaults. To activate the profiles in addition to the defaults, prepend +them with a `+`: - $ lein with-profile +server run + $ lein with-profile +server,+fast run -You can also use `-` to deactivate a profile. +You can also use `-` to deactivate profiles. By default all profiles will share the same `:target-path`, which can cause problems if settings from one profile leak over into @@ -227,8 +227,11 @@ This can be used to avoid duplication: :production [:shared :prod-servers]} ``` -It is not recommended to make a composite profile which contains both -keywords and maps; they should either be all keywords or all maps. +The vector should contain keywords referencing other profiles which +will be merged together. + +While it is possible to make a composite profile which contains both +keywords and maps, this will become an error in a future version of Leiningen. Composite profiles also cannot have certain types of metadata propagated, which makes them incompatible with the `:provided` @@ -252,7 +255,7 @@ Here is an example of such a case: ## Debugging To see how a given profile affects your project map, use the -[lein-pprint](https://github.com/technomancy/leiningen/tree/stable/lein-pprint) +[lein-pprint](https://codeberg.org/leiningen/leiningen/src/stable/lein-pprint) plugin: $ lein with-profile 1.4 pprint diff --git a/doc/TEMPLATES.md b/doc/TEMPLATES.md index 93e2f5d71..e71293c40 100644 --- a/doc/TEMPLATES.md +++ b/doc/TEMPLATES.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [Writing Templates](#writing-templates) - [Structure](#structure) @@ -67,7 +67,7 @@ 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). +templates](https://codeberg.org/leiningen/leiningen/src/stable/resources/leiningen/new). ## Testing Your Template diff --git a/doc/TUTORIAL.md b/doc/TUTORIAL.md index 51d397f1f..0dcd08b0e 100644 --- a/doc/TUTORIAL.md +++ b/doc/TUTORIAL.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [Tutorial](#tutorial) - [What This Tutorial Covers](#what-this-tutorial-covers) @@ -37,7 +37,7 @@ 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). +[let us know](https://codeberg.org/leiningen/leiningen/issues/new). It offers various project-related tasks and can: @@ -63,8 +63,8 @@ tool. 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](http://ant.apache.org/) or [Maven](https://maven.apache.org/) in anger: don't panic. Leiningen is designed +For those of you new to the JVM who have never touched [Ant](https://ant.apache.org/) with you in mind. This tutorial will help you get started and explain Leiningen's take on project automation and JVM-land dependency management. @@ -102,7 +102,7 @@ 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). +[README](https://codeberg.org/leiningen/leiningen/src/stable/README.md). Generating a new project is easy: $ lein new app my-stuff @@ -161,7 +161,7 @@ read up on them elsewhere, for example [here](https://8thlight.com/blog/colin-jo Your `project.clj` file will start off looking something like this: -```clj +```clojure (defproject my-stuff "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "https://example.com/FIXME" @@ -271,7 +271,7 @@ 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) +[sample.project.clj](https://codeberg.org/leiningen/leiningen/src/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. @@ -323,12 +323,13 @@ resolved, either from a remote repo or via `lein install` locally. 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"] - ...] - +```clj +: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 @@ -336,7 +337,7 @@ hierarchy doesn't need to appear in the way `commons` is actually laid out on di 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", +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 @@ -365,14 +366,14 @@ Central and Clojars is supported. ### Maven Read Timeout -The underlying [Maven Wagon](https://maven.apache.org/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`: +The underlying [Maven Wagon](https://maven.apache.org/wagon/) +transport reads the `maven.wagon.rto` system property to determine the +timeout (in milliseconds) used when communicating with a repository. +If the default timeout isn't right, it can be overridden via +`LEIN_JVM_OPTS`: ```bash -export LEIN_JVM_OPTS="-Dmaven.wagon.rto=1800000" +export LEIN_JVM_OPTS="-Dmaven.wagon.rto=30000" ``` ## Setting JVM Options @@ -381,13 +382,13 @@ To pass extra arguments to the JVM, set the `:jvm-opts` vector. This will overri any default JVM opts set by Leiningen. ```clj - :jvm-opts ["-Xmx1g"] +: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. -``` +```clj :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. @@ -496,6 +497,16 @@ 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. +The built-in `test` command wraps the basic runner from `clojure.test` +and adds a few small features, but many people prefer to replace it +with a more full-featured test runner like [kaocha](https://github.com/lambdaisland/kaocha). +By adding an alias for `test` along with an entry in `:dependencies`, +it's easy to make a third-party runner replace the built-in test task: + +```clj +:aliases {"test" ["run" "-m" "kaocha.runner"]} +``` + 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, @@ -653,8 +664,7 @@ 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](https://en.wikipedia.org/wiki/Tar_(computing)) with accompanied shell scripts using the [lein-tar plugin](https://github.com/technomancy/lein-tar) -and then deployed using [pallet](http://palletops.com/), [chef](https://chef.io/), -or other mechanisms. +and then deployed using [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](https://en.wikipedia.org/wiki/WAR_(file_format)) @@ -672,7 +682,7 @@ 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). +[unrepeatable deployments](https://wiki.leiningen.org/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 @@ -703,7 +713,7 @@ Given these pitfalls, it's best to use an uberjar if possible. 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) +repository](https://codeberg.org/leiningen/leiningen/src/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 @@ -747,9 +757,10 @@ 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 +will attempt to sign it using [GPG](https://gnupg.org) or +[SSH](https://www.agwa.name/blog/post/ssh_signatures) to prove your authorship of the release. See the -[deploy guide](https://github.com/technomancy/leiningen/blob/stable/doc/DEPLOY.md) +[deploy guide](https://codeberg.org/leiningen/leiningen/src/stable/doc/DEPLOY.md) for details of how to set that up. The deploy guide includes instructions for deploying to other repositories as well. diff --git a/doc/ja/PLUGINS_ja.md b/doc/ja/PLUGINS_ja.md index 2d9e7303d..ecf1b0b58 100644 --- a/doc/ja/PLUGINS_ja.md +++ b/doc/ja/PLUGINS_ja.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [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) @@ -36,9 +36,9 @@ Leiningenのタスクはleiningen.$TASK名前空間にある$TASKという名前 ## プラグインを書く `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)がプラグインから利用可能です。 +[Leiningen本体の依存関係全て](https://codeberg.org/leiningen/leiningen/src/stable/project.clj)がプラグインから利用可能です。 -非常に単純なプラグインの例として、 [ソースコード内の](https://github.com/technomancy/leiningen/tree/stable/lein-pprint) +非常に単純なプラグインの例として、 [ソースコード内の](https://codeberg.org/leiningen/leiningen/src/stable/lein-pprint) `lein-pprint`ディレクトリを参照してください。 プラグインの開発中、プロジェクト内で`lein install`を再実行し、それからテストプロジェクトに切り替えるのは非常に手間がかかります。一度プラグインをインストールすれば、テストプロジェクト内の`.lein-classpath`ファイルに、プラグインの`src`ディレクトリのパスを記述しておくことでこの手間を省くことができます。そのプラグインが別の開発中のライブラリに依存している場合は、`.lein-classpath`にUNIXでは`:`、Windowsでは`;`のクラスパスセパレータで区切ってライブラリのディレクトリを追加することができます。 @@ -285,7 +285,7 @@ Leiningenタスクを記述する必要があるのは、例えば`eval-in-proje この例ではプロジェクトマップの`:version`フィールドを引数リストに渡すことで、プロジェクト内で実行される`-main`関数が値にアクセスできるようにしています。 -こういった例の多くは[既存のプラグイン](https://github.com/technomancy/leiningen/wiki/plugins)でカバーされているはずですが、もし類似の例が見つからず、何らかの理由で別のブラグインに分離できない場合、`tasks/leiningen/`の下に新しいタスクを定義した`foo.clj`ファイルを作成し、`tasks`を`.lein-classpath`に追加することでこのふるまいを実現することができます。 +こういった例の多くは[既存のプラグイン](https://wiki.leiningen.org/Plugins)でカバーされているはずですが、もし類似の例が見つからず、何らかの理由で別のブラグインに分離できない場合、`tasks/leiningen/`の下に新しいタスクを定義した`foo.clj`ファイルを作成し、`tasks`を`.lein-classpath`に追加することでこのふるまいを実現することができます。 ``` $ ls @@ -304,7 +304,7 @@ Hello, Foo! ## 楽しんでください -あなたのプラグインができあがったら、[Wiki上のリスト](https://github.com/technomancy/leiningen/wiki/plugins)に追加してください。 +あなたのプラグインができあがったら、[Wiki上のリスト](https://github.com/technomnacy/leiningen/wiki/plugins)に追加してください。 このプラグインシステムが、あなたの思いのままにLeiningenをカスタマイズするための簡単で、柔軟なシステムを提供していることを願っています。 diff --git a/doc/ja/TUTORIAL_ja.md b/doc/ja/TUTORIAL_ja.md index f9c84a276..95420a96d 100644 --- a/doc/ja/TUTORIAL_ja.md +++ b/doc/ja/TUTORIAL_ja.md @@ -1,6 +1,6 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* +**Table of Contents** - [チュートリアル](#%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB) - [このチュートリアルの取り扱い範囲](#%E3%81%93%E3%81%AE%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%E3%81%AE%E5%8F%96%E3%82%8A%E6%89%B1%E3%81%84%E7%AF%84%E5%9B%B2) @@ -38,7 +38,7 @@ Leiningen は Clojure プロジェクトを、髪の毛が燃え上がるような思いをせずに、 自動化するためのものです。もしこのチュートリアルにしたがっていて、 髪の毛が燃え上がるような思いをしたり何かイライラするようなことがあった場合は、 -ぜひ[私達に知らせてください](https://github.com/technomancy/leiningen/issues/new)。 +ぜひ[私達に知らせてください](https://codeberg.org/leiningen/leiningen/issues/new)。 Leiningen は様々なプロジェクトに関連するタスクを提案します: @@ -109,7 +109,7 @@ Leiningen は*プロジェクト*とともに動作します。 ## プロジェクトの作成 わたしたちは、あなたが -[README](https://github.com/technomancy/leiningen/blob/stable/README.md) +[README](https://codeberg.org/leiningen/leiningen/src/stable/README.md) にしたがって Leiningen をインストールしたと仮定します。 この時新しいプロジェクトを生成することは簡単です: @@ -282,7 +282,7 @@ maven レポジトリで、 [Central](https://search.maven.org/) は サードパーティのレポジトリは `:repositories` キーを project.clj に指定することで追加出来ます。 どのようにすれば良いのか -[sample.project.clj](https://github.com/technomancy/leiningen/blob/stable/sample.project.clj) +[sample.project.clj](https://codeberg.org/leiningen/leiningen/src/stable/sample.project.clj) を見てみましょう。このサンプルは追加のレポジトリとして Sonatype レポジトリを使っていますが、 これは(Clojure や Java の)ライブラリの、最新のスナップショット開発バージョンへのアクセスを提供します。 このサンプルには同様に、レポジトリに関連する更新頻度などの設定が含まれています。 @@ -690,7 +690,7 @@ uberjar 以上のことをしようとした場合、サーバサイドデプロ Leiningen の自分自身の JVM は実行され続け、不必要なメモリを消費します。 加えて非常に重要なこととして、デプロイする前に全ての依存関係を凍結するステップを踏まなければなりません。 -そうしなければ[繰り返せないデプロイ](https://github.com/technomancy/leiningen/wiki/Repeatability) +そうしなければ[繰り返せないデプロイ](https://wiki.leiningen.org/Repeatability) 問題によって止まってしまいます。一つのデプロイ(tar ファイル, .deb ファイルなど)にプロジェクトのコードに加えて、 `~/.m2/repository` を含むことを検討すべきです。継続インテグレーションを設定する際には、 デプロイ可能なアーティファクトを作るために Leiningen を使う事が推奨されます。 @@ -716,7 +716,7 @@ Leiningen の自分自身の JVM は実行され続け、不必要なメモリ もしプロジェクトがライブラリで、他の人がプロジェクトの中で 依存関係としてそのライブラリを使えるようにしたいときは、 そのライブラリをパブリックレポジトリに置く必要が出てきます。 -自分自身の[プライベートレポジトリを運用する](https://github.com/technomancy/leiningen/blob/stable/doc/DEPLOY.md) +自分自身の[プライベートレポジトリを運用する](https://codeberg.org/leiningen/leiningen/src/stable/doc/DEPLOY.md) こともできますし、 [Central](https://search.maven.org)に置くことも出来ますが、 最も簡単なのは[Clojars](https://clojars.org)で公開する方法でしょう。 @@ -749,7 +749,7 @@ Leiningen の自分自身の JVM は実行され続け、不必要なメモリ スナップショット版ではなくリリース版をデプロイするときは、 Leiningen は [GPG](https://gnupg.org) を使って署名を行い、 リリースの著作権を証明します。どのように設定を行うかの詳細については、 -[デプロイガイド](https://github.com/technomancy/leiningen/blob/stable/doc/DEPLOY.md)を参考にしてください。 +[デプロイガイド](https://codeberg.org/leiningen/leiningen/src/stable/doc/DEPLOY.md)を参考にしてください。 デプロイガイドでは他のレポジトリへのデプロイ方法の説明もしています。 ## おわり! diff --git a/doc/ja/lein_ja.1 b/doc/ja/lein_ja.1 index 9f949ad6c..9e22d68e9 100644 --- a/doc/ja/lein_ja.1 +++ b/doc/ja/lein_ja.1 @@ -173,7 +173,7 @@ Leiningen はその設定ファイルとして、プロジェクトのルート .SH バグ -https://github.com/technomancy/leiningen/issues を見て、 +https://codeberg.org/leiningen/leiningen/issues を見て、 あなたの問題が既知のものかどうか確認してください。 その際には、 diff --git a/doc/lein.1 b/doc/lein.1 index f66fe2b89..5c1175fcc 100644 --- a/doc/lein.1 +++ b/doc/lein.1 @@ -172,7 +172,7 @@ You can customize your project map further with profiles; see .SH BUGS -Check https://github.com/technomancy/leiningen/issues to see if your +Check https://codeberg.org/leiningen/leiningen/issues to see if your problem is a known issue. If not, please open a new issue on that site. Please include the output of .B lein version diff --git a/lein-pprint/project.clj b/lein-pprint/project.clj index 92dea4ffa..1f022ddff 100644 --- a/lein-pprint/project.clj +++ b/lein-pprint/project.clj @@ -1,6 +1,6 @@ -(defproject lein-pprint "1.3.2" +(defproject lein-pprint "1.3.3-SNAPSHOT" :description "Pretty-print a representation of the project map." - :url "https://github.com/technomancy/leiningen" + :url "https://codeberg.org/leiningen/leiningen" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} :eval-in-leiningen true) diff --git a/leiningen-core/README.md b/leiningen-core/README.md index fa2c30d4d..b79a7b368 100644 --- a/leiningen-core/README.md +++ b/leiningen-core/README.md @@ -5,9 +5,6 @@ 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 @@ -32,7 +29,7 @@ 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) +[plugin guide](https://codeberg.org/leiningen/leiningen/src/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. @@ -69,7 +66,6 @@ itself, there's no need to enforce this isolation. ## License -Copyright © 2011-2021 Phil Hagelberg and -[contributors](https://github.com/technomancy/leiningen/graphs/contributors). +Copyright © 2011-2022 Phil Hagelberg and contributors. Distributed under the Eclipse Public License, the same as Clojure. diff --git a/leiningen-core/dev-resources/leiningen/downloads.clj b/leiningen-core/dev-resources/leiningen/downloads.clj deleted file mode 100644 index 107e8933d..000000000 --- a/leiningen-core/dev-resources/leiningen/downloads.clj +++ /dev/null @@ -1,110 +0,0 @@ -(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... diff --git a/leiningen-core/pom.xml b/leiningen-core/pom.xml index b96f2ad73..63bab4c33 100644 --- a/leiningen-core/pom.xml +++ b/leiningen-core/pom.xml @@ -1,121 +1,160 @@ - - - 4.0.0 - leiningen-core - leiningen-core - jar - 2.9.9-SNAPSHOT - leiningen-core - Library for core functionality of Leiningen. - https://github.com/technomancy/leiningen - - - Eclipse Public License - http://www.eclipse.org/legal/epl-v10.html - - - - 466ba77e53a689242d5124eb76f6832838042a9b - - - src - test - - - resources - - - - - resources - - - target - target/classes - - - - - central - https://repo1.maven.org/maven2/ - - false - - - true - - - - clojars - https://repo.clojars.org/ - - true - - - true - - - - - - - - - org.clojure - clojure - 1.11.1 - - - timofreiberg - bultitude - 0.3.0 - - - clojure - org.clojure - - - - - org.flatland - classlojure - 0.7.1 - - - robert - hooke - 1.3.0 - - - clj-commons - pomegranate - 1.2.1 - - - jcl-over-slf4j - org.slf4j - - - - - com.hypirion - io - 0.3.1 - - - org.slf4j - slf4j-nop - 1.7.25 - - - org.clojure - tools.macro - 0.1.5 - - - + + + 4.0.0 + leiningen-core + leiningen-core + jar + 2.11.3-SNAPSHOT + leiningen-core + Library for core functionality of Leiningen. + https://codeberg.org/leiningen/leiningen + + + Eclipse Public License + https://www.eclipse.org/legal/epl-v10.html + + + + https://github.com/cdzwm/leiningen + scm:git:git://github.com/cdzwm/leiningen.git + scm:git:ssh://git@github.com/cdzwm/leiningen.git + 78b732819a61f7bf868fbd28589a9e690b0bfaea + + + src + test + + + resources + + + + + resources + + + target + target\classes + + + + + central + https://repo1.maven.org/maven2/ + + false + + + true + + + + clojars + https://repo.clojars.org/ + + true + + + true + + + + + + + + + org.clojure + clojure + 1.11.1 + + + timofreiberg + bultitude + 0.3.0 + + + clojure + org.clojure + + + dynapath + org.tcrawley + + + + + org.flatland + classlojure + 0.7.1 + + + robert + hooke + 1.3.0 + + + clj-commons + pomegranate + 1.2.24 + + + jcl-over-slf4j + org.slf4j + + + slf4j-api + org.slf4j + + + wagon-provider-api + org.apache.maven.wagon + + + httpcore + org.apache.httpcomponents + + + httpclient + org.apache.httpcomponents + + + + + com.hypirion + io + 0.3.1 + + + org.slf4j + slf4j-nop + 1.7.25 + + + org.clojure + tools.macro + 0.1.5 + + + org.apache.maven.wagon + wagon-http + 3.5.3 + + + slf4j-api + org.slf4j + + + + + commons-io + commons-io + 2.6 + + + + https://codeberg.org/leiningen/leiningen --> diff --git a/leiningen-core/project.clj b/leiningen-core/project.clj index 52f4fb745..0ee7086b2 100644 --- a/leiningen-core/project.clj +++ b/leiningen-core/project.clj @@ -1,20 +1,29 @@ -(defproject leiningen-core "2.9.9-SNAPSHOT" - :url "https://github.com/technomancy/leiningen" +(defproject leiningen-core "2.11.3-SNAPSHOT" + :url "https://codeberg.org/leiningen/leiningen" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://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.11.1"] [timofreiberg/bultitude "0.3.0" - :exclusions [org.clojure/clojure]] + :exclusions [org.clojure/clojure + org.tcrawley/dynapath]] [org.flatland/classlojure "0.7.1"] [robert/hooke "1.3.0"] - [clj-commons/pomegranate "1.2.1" - :exclusions [org.slf4j/jcl-over-slf4j]] + [clj-commons/pomegranate "1.2.24" + :exclusions [org.slf4j/jcl-over-slf4j org.slf4j/slf4j-api + org.apache.maven.wagon/wagon-provider-api + org.apache.httpcomponents/httpcore + org.apache.httpcomponents/httpclient]] [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"]] + [org.clojure/tools.macro "0.1.5"] + ;; this new version doesn't bring in a dependency on + ;; an insecure version of jsoup + [org.apache.maven.wagon/wagon-http "3.5.3" + :exclusions [org.slf4j/slf4j-api]] + [commons-io/commons-io "2.6"]] :scm {:dir ".."} :dev-resources-path "dev-resources" :aliases {"bootstrap" ["with-profile" "base" diff --git a/leiningen-core/src/leiningen/core/classpath.clj b/leiningen-core/src/leiningen/core/classpath.clj index 9c7964226..147179b3e 100644 --- a/leiningen-core/src/leiningen/core/classpath.clj +++ b/leiningen-core/src/leiningen/core/classpath.clj @@ -8,7 +8,8 @@ [leiningen.core.user :as user] [leiningen.core.utils :as utils] [leiningen.core.pedantic :as pedantic]) - (:import (java.util.jar JarFile) + (:import (java.io File) + (java.util.jar JarEntry JarFile) (org.eclipse.aether.resolution DependencyResolutionException))) (defn- warn [& args] @@ -35,13 +36,13 @@ (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] + [native-path ^File 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)) + ^JarFile jar (try (JarFile. file) + (catch Exception e + (throw (Exception. (format "Problem opening jar %s" file) e))))] + (doseq [^JarEntry 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)))] @@ -213,7 +214,7 @@ So, a credentials map that contains an entry: - {#\"http://maven.company.com/.*\" {:username \"abc\" :password \"xyz\"}} + {#\"https://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." diff --git a/leiningen-core/src/leiningen/core/eval.clj b/leiningen-core/src/leiningen/core/eval.clj index 53fefcdd7..71762b6e3 100644 --- a/leiningen-core/src/leiningen/core/eval.clj +++ b/leiningen-core/src/leiningen/core/eval.clj @@ -170,6 +170,8 @@ (map #(str (name (key %)) "=" (val %))) (into-array String))) +(def ^:dynamic *sh-silent?* false) + (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] @@ -182,14 +184,15 @@ (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) + (let [pump-out (or *sh-silent?* (doto (Pipe. out System/out) .start)) + pump-err (or *sh-silent?* (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) + (when (not *sh-silent?*) + (.join pump-out) + (.join pump-err)) (let [exit-value (.waitFor proc)] (when *pump-in* (.kill System/in) @@ -238,7 +241,13 @@ (File/createTempFile "form-init" ".clj") (io/file (:target-path project) (str checksum "-init.clj")))] (spit init-file - (binding [*print-dup* *eval-print-dup*] + ;; NOTE: we can't include metadata in the printed forms by default, because this breaks + ;; some plugins (when metadata includes objects that don't have a tagged + ;; literal reader). Requires opt-in via `:preserve-eval-meta true`. + ;; See https://github.com/technomancy/leiningen/issues/2328 and + ;; https://github.com/technomancy/leiningen/issues/2814 + (binding [*print-dup* *eval-print-dup* + *print-meta* (:preserve-eval-meta project)] (pr-str (when-not (System/getenv "LEIN_FAST_TRAMPOLINE") `(.deleteOnExit (File. ~(.getCanonicalPath init-file)))) form))) @@ -310,18 +319,20 @@ (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) + (require 'nrepl.transport) + (let [port-file (io/file (:root project) ".nrepl-port") + connect (resolve 'nrepl.core/connect) + client (resolve 'nrepl.core/client) + client-session (resolve 'nrepl.core/client-session) + message (resolve 'nrepl.core/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*] + (message client {:op "eval" :code (binding [*print-dup* *eval-print-dup* + *print-meta* (:preserve-eval-meta project)] (pr-str form))}) (doseq [{:keys [out err status session] :as msg} (repeatedly #(recv transport 100)) @@ -352,18 +363,19 @@ (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) + (binding [*print-meta* (:preserve-eval-meta project)] + ((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" + to avoid the Gilardi Scenario: https://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;" + (main/warn ";; WARNING: :warn-on-reflection is deprecated in project.clj;" "use :global-vars.")) (eval-in project `(do (set! ~'*warn-on-reflection* diff --git a/leiningen-core/src/leiningen/core/main.clj b/leiningen-core/src/leiningen/core/main.clj index 72a3c0a10..0fec2d303 100644 --- a/leiningen-core/src/leiningen/core/main.clj +++ b/leiningen-core/src/leiningen/core/main.clj @@ -378,15 +378,15 @@ These get replaced with the corresponding values from the project map." ;; packagers should replace this string! (def ^:private min-version-warning - "*** Warning: This project requires Leiningen %s, but you have %s *** + ";; *** 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\".") +;; Get the latest version of Leiningen from your package manager 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))))) + (warn (format min-version-warning min-lein-version (leiningen-version))))) (defn user-agent [] (format "Leiningen/%s (Java %s; %s %s; %s)" @@ -418,35 +418,32 @@ Get the latest version of Leiningen at https://leiningen.org or by executing :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- init-dynamic [] + (project/ensure-dynamic-classloader) + (user/init)) + +(defn- init-static [] + (require 'leiningen.static-classpath) + (let [no-load (fn [& _] (throw (Exception. "static-classpath can't load")))] + (alter-var-root #'*read-eval* (constantly false)) + (alter-var-root #'eval (constantly no-load)) + (alter-var-root #'load-file (constantly no-load)))) (defn -main "Command-line entry point." [& raw-args] (try - (project/ensure-dynamic-classloader) - (aether/register-wagon-factory! "http" insecure-http-abort) - (user/init) + ;; it would be tidier if this could be kept as metadata on the task var + ;; itself, but it's needed before we resolve the task, so we must hard-code + (if (= "static-classpath" (first raw-args)) + (init-static) + (init-dynamic)) (binding [project/*memoize-middleware* true] - (let [project (if (.exists (io/file *cwd* "project.clj")) - (project/read (str (io/file *cwd* "project.clj"))) - (default-project))] + (let [project (cond (= "static-classpath" (first raw-args)) + {:root *cwd*} + (.exists (io/file *cwd* "project.clj")) + (project/read (str (io/file *cwd* "project.clj"))) + :else (default-project))] (when (:exact-lein-version project) (verify-exact-version project)) (when (:min-lein-version project) (verify-min-version project)) (configure-http) diff --git a/leiningen-core/src/leiningen/core/pedantic.clj b/leiningen-core/src/leiningen/core/pedantic.clj index b75081efa..f413d795f 100644 --- a/leiningen-core/src/leiningen/core/pedantic.clj +++ b/leiningen-core/src/leiningen/core/pedantic.clj @@ -22,11 +22,20 @@ * `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))) + (:require [cemerick.pomegranate.aether :as aether] + [clojure.set :as set]) + (:import (java.util Map) + (org.eclipse.aether DefaultRepositorySystemSession) + (org.eclipse.aether.artifact Artifact) + (org.eclipse.aether.collection DependencyGraphTransformationContext + DependencyGraphTransformer) + (org.eclipse.aether.graph Dependency + DependencyNode + Exclusion) + (org.eclipse.aether.util.graph.transformer ConflictIdSorter + TransformationContextKeys))) + +(set! *warn-on-reflection* true) (defn- warn [& args] ;; TODO: remove me once #1227 is merged @@ -43,7 +52,7 @@ (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] + [node ^DependencyGraphTransformationContext context] (when-not (.get context TransformationContextKeys/SORTED_CONFLICT_IDS) (-> (ConflictIdSorter.) (.transformGraph node context)))) @@ -51,7 +60,7 @@ (defn- range? "Does the path point to a DependencyNode asking for a version range which contains several versions?" - [{:keys [node]}] + [{:keys [^DependencyNode node]}] (when-let [vc (.getVersionConstraint node)] (let [range (.getRange vc) lb (some-> range .getLowerBound) @@ -67,24 +76,13 @@ (defn- node< "Is the version of node1 < version of node2." - [node1 node2] + [^DependencyNode node1 ^DependencyNode 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))) + [^DependencyNode n1 ^DependencyNode n2] + (= (.getArtifact n1) (.getArtifact n2))) (defn- top-level? "Is the path a top level dependency in the project?" @@ -92,6 +90,12 @@ ;; Parent is root node (= 1 (count parents))) +(defn- different-paths? + "Work around a bug in DependencyNode where equality is broken." + [{node1 :node parents1 :parents} {node2 :node parents2 :parents}] + (not (and (node= node1 node2) + (every? true? (map node= parents1 parents2))))) + (defn- set-overrides! "Check each `accepted-path` against its conflicting paths. If a conflicting path fails the pedantic criteria then add information @@ -99,7 +103,7 @@ [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) + :when (and (different-paths? path conflict-path) ;; This is the pedantic criteria (or (node< node (:node conflict-path)) (top-level? conflict-path)))] @@ -110,26 +114,35 @@ :ranges (filter #(node= (:node %) node) ranges)}))))) +(defn- paths->deps + [paths] + (->> paths + (map (fn [{:keys [^DependencyNode node]}] (.getDependency node))) + (into #{}))) + (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 []] + results [] + visited-deps #{}] (if (empty? paths) results - (recur (for [{:keys [node parents]} paths - :when (not (some #{node} parents)) + (recur (for [{:keys [^DependencyNode node parents]} paths + :when (not (contains? visited-deps (.getDependency node))) c (.getChildren node)] - {:node c - :parents (conj parents node)}) - (doall (concat results paths)))))) + {:node c :parents (conj parents node)}) + (into results paths) + (set/union visited-deps (paths->deps 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] + [ranges overrides node + ^DependencyGraphTransformationContext context + ^DependencyGraphTransformer transformer] ;; Force initialization of the context like NearestVersionConflictResolver (initialize-conflict-ids! node context) ;; Get all the paths of the graph before dependency resolution @@ -139,9 +152,9 @@ ;; 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) + (let [^Map 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)) + (update acc (.get node->id node) conj path)) {} ;; Remove ranges as they cause problems and were ;; warned above @@ -165,7 +178,7 @@ paths that were not used. `:ranges` is a list of paths containing version ranges that might have affected the resolution." - [session ranges overrides] + [^DefaultRepositorySystemSession session ranges overrides] (let [transformer (.getDependencyGraphTransformer session)] (.setDependencyGraphTransformer session @@ -185,7 +198,7 @@ #(-> % aether/repository-session (use-transformer ranges overrides)))) -(defn- group-artifact [artifact] +(defn- group-artifact [^Artifact artifact] (if (= (.getGroupId artifact) (.getArtifactId artifact)) (.getGroupId artifact) @@ -193,8 +206,16 @@ "/" (.getArtifactId artifact)))) -(defn- dependency-str [dependency & [version]] - (if-let [artifact (and dependency (.getArtifact dependency))] +(defn- exclusion-group-artifact [^Exclusion exclusion] + (if (= (.getGroupId exclusion) + (.getArtifactId exclusion)) + (.getGroupId exclusion) + (str (.getGroupId exclusion) + "/" + (.getArtifactId exclusion)))) + +(defn- dependency-str [^Dependency dependency & [version]] + (if-let [^Artifact artifact (and dependency (.getArtifact dependency))] (str "[" (group-artifact artifact) " \"" (or version (.getVersion artifact)) "\"" @@ -205,13 +226,14 @@ (if (not= extension "jar") (str " :extension \"" extension "\""))) (if-let [exclusions (seq (.getExclusions dependency))] - (str " :exclusions " (mapv (comp symbol group-artifact) + (str " :exclusions " (mapv (comp symbol exclusion-group-artifact) exclusions))) "]"))) (defn- message-for [path & [show-constraint?]] (->> path - (map #(dependency-str (.getDependency %) (.getVersionConstraint %))) + (map (fn [^DependencyNode node] + (dependency-str (.getDependency node) (.getVersionConstraint node)))) (remove nil?) (interpose " -> ") (apply str))) @@ -219,8 +241,8 @@ (defn- message-for-version [{:keys [node parents]}] (message-for (conj parents node))) -(defn- exclusion-for-range [node parents] - (if-let [top-level (second parents)] +(defn- exclusion-for-range [^DependencyNode node parents] + (if-let [^DependencyNode top-level (second parents)] (let [excluded-artifact (.getArtifact (.getDependency node)) exclusion (Exclusion. (.getGroupId excluded-artifact) (.getArtifactId excluded-artifact) "*" "*") @@ -238,11 +260,30 @@ (defn- exclusion-for-override [{:keys [node parents]}] (exclusion-for-range node parents)) -(defn- message-for-override [{:keys [accepted ignoreds ranges]}] +(defn- dep-str-version [node] + (-> node :node .getVersion .toString)) + +(defn- newest-dep [{accepted :accepted + ignoreds :ignoreds + _ranges :ranges}] + (let [dep-name (str (-> accepted :node .getArtifact .getGroupId) + "/" + (-> accepted :node .getArtifact .getArtifactId)) + dep-version (some->> (conj ignoreds accepted) + (sort-by :node node<) + last + dep-str-version)] + (str "[" dep-name " \"" dep-version "\"]"))) + +(defn- print-dep-suggest [overrides] + (run! #(->> % newest-dep warn) overrides)) + +(defn- message-for-override [{:keys [accepted ignoreds ranges] :as override}] {:accepted (message-for-version accepted) :ignoreds (map message-for-version ignoreds) :ranges (map message-for-range ranges) - :exclusions (map exclusion-for-override ignoreds)}) + :exclusions (map exclusion-for-override ignoreds) + :override override}) (defn- pedantic-print-ranges [messages] (when-not (empty? messages) @@ -254,7 +295,7 @@ (defn- pedantic-print-overrides [messages] (when-not (empty? messages) (warn "Possibly confusing dependencies found:") - (doseq [{:keys [accepted ignoreds ranges exclusions]} messages] + (doseq [{:keys [accepted ignoreds ranges exclusions override]} messages] (warn accepted) (warn " overrides") (doseq [ignored (interpose " and" ignoreds)] @@ -266,6 +307,11 @@ (warn "\nConsider using these exclusions:") (doseq [ex (distinct exclusions)] (warn ex)) + (warn) + (warn "OR") + (warn) + (warn "Adding the next line to the head of the project.clj file's depency vector:") + (print-dep-suggest [override]) (warn)))) (alter-var-root #'pedantic-print-ranges memoize) @@ -280,7 +326,12 @@ (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))) + (pedantic-print-overrides (map message-for-override overrides)) + (when (not-empty overrides) + (warn "\nIn addition to using above exclusion method, you can also add all the following lines\nto the head of the depency vector of your project.clj to resolve the confusing dependencies' problem:\n") + (print-dep-suggest overrides) + (warn (apply str (repeat 40 \-))) + (warn))) (when (and abort-or-true (not (empty? (concat ranges overrides)))) (require 'leiningen.core.main) diff --git a/leiningen-core/src/leiningen/core/project.clj b/leiningen-core/src/leiningen/core/project.clj index 59f981920..41fdd0a2b 100644 --- a/leiningen-core/src/leiningen/core/project.clj +++ b/leiningen-core/src/leiningen/core/project.clj @@ -35,7 +35,7 @@ (require 'leiningen.core.main) (apply (resolve 'leiningen.core.main/warn) args)) -(def ^:private warn-once (memoize warn)) +(def ^:internal warn-once (memoize warn)) (defn- update-each-contained [m keys f & args] (reduce (fn [m k] @@ -465,6 +465,26 @@ (meta dependencies))) project))) +(defn- remove-self-excluded-deps + "Remove any dependency that contains it's dependency id inside it's own + :exclusions vec." + [{:keys [dependencies] :as project}] + (if dependencies + (update project :dependencies + (fn [deps] + (when deps + (let [self-excluded? (fn [dep] + (let [{:keys [artifact-id group-id exclusions]} (dependency-map dep)] + (some (fn [{excl-art-id :artifact-id, excl-grp-id :group-id}] + (and + (= group-id excl-grp-id) + (= artifact-id excl-art-id))) + exclusions)))] + (with-meta + (remove self-excluded? deps) + (meta deps)))))) + project)) + (defn- absolutize [root path] (str (if (.isAbsolute (io/file path)) path @@ -518,7 +538,9 @@ (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)))) + (str/join "+" (->> (normalize-profile-names project profiles) + (map n) + (remove #{"default"})))) project))) (defn target-path-subdirs [{:keys [target-path] :as project} key] @@ -558,7 +580,7 @@ :test-selectors {:default (with-meta '(constantly true) {:displace true})} ;; bump deps in leiningen's own project.clj with these - :dependencies '[^:displace [nrepl/nrepl "0.9.0" + :dependencies '[^:displace [nrepl/nrepl "1.0.0" :exclusions [org.clojure/clojure]] ^:displace [org.nrepl/incomplete "0.1.0" :exclusions [org.clojure/clojure]]] @@ -615,7 +637,7 @@ (do (warn-once left "and" right "have a type mismatch merging profiles.") right))) -(defn- apply-profiles [project profiles] +(defn ^:internal apply-profiles [project profiles] (reduce (fn [project profile] (with-meta (meta-merge project profile) @@ -623,6 +645,16 @@ project profiles)) +(defn- warn-composite [profile] + (when (and (composite-profile? profile) + (not (keyword-composite-profile? profile))) + ;; TODO: include suggestion for how to move map to top-level profile + (warn-once + "Composite profiles containing maps are strongly recommended against." + "\nSupport will be removed in future versions of Leiningen due to subtle" + "\nunexpected behavior. Move the map from the composite profile to its own" + "\ntop-level named profile to avoid issues.\n" (pr-str profile)))) + (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 @@ -640,7 +672,8 @@ (lookup-profile* profiles result)) (composite-profile? profile) - (apply-profiles {} (map (partial lookup-profile* profiles) profile)) + (apply-profiles {} (map (partial lookup-profile* profiles) + (doto profile warn-composite))) :else (or profile {}))) @@ -701,7 +734,7 @@ (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")))) + "https://wiki.leiningen.org/Repeatability")))) (defn- warn-user-profile [root profiles] (when (and root (contains? profiles :user)) @@ -921,13 +954,16 @@ "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)) + (let [project (-> (:without-profiles (meta project) project) + (with-meta (meta project)) + (vary-meta dissoc :active-profiles)) include-profiles-meta (->> (expand-profiles-with-meta project include-profiles) (utils/last-distinct-by first)) - effective-include-profiles (map first include-profiles-meta) + ;; We want to remove the exclude-profiles earlier, but if we expand + ;; earlier on we lose the pom-scope metadata from the profile. + effective-include-profiles (remove (set exclude-profiles) + (map first include-profiles-meta)) exclude-profiles (utils/last-distinct (expand-profiles project exclude-profiles)) profile-map (apply dissoc (:profiles (meta project)) exclude-profiles) profiles (for [profile-name effective-include-profiles] @@ -944,6 +980,7 @@ (target-path-subdirs :native-path) (absolutize-paths) (add-global-exclusions) + (remove-self-excluded-deps) (vary-meta merge {:without-profiles project :included-profiles include-profiles :excluded-profiles exclude-profiles @@ -987,6 +1024,10 @@ (let [{:keys [included-profiles excluded-profiles]} (meta project) profiles (expand-profiles project profiles)] (set-profiles project + ;; we need un-expanded profiles here because if :dev was + ;; a composite profile that included :foo, we need to start + ;; from :dev in order to ensure :foo's dependencies have + ;; test scope in the pom. (remove (set profiles) included-profiles) (concat excluded-profiles profiles)))) diff --git a/leiningen-core/src/leiningen/core/user.clj b/leiningen-core/src/leiningen/core/user.clj index 99b46be79..2733ff9ba 100644 --- a/leiningen-core/src/leiningen/core/user.clj +++ b/leiningen-core/src/leiningen/core/user.clj @@ -19,13 +19,28 @@ [name] (System/getenv name)) +(defn- existing-file [f] (and f (.exists f) f)) + +(def ^:private warn-once (memoize (fn [& args] + (binding [*out* *err*] + (apply println args))))) + (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)))) + (let [home (System/getProperty "user.home") + explicit-home (getenv "LEIN_HOME") + home-home (io/file home ".lein") + xdg-home (io/file (or (getenv "XDG_CONFIG_HOME") + (str home "/.config")) "leiningen")] + (when (and (existing-file home-home) (existing-file xdg-home)) + (warn-once "Warning: found multiple config directories:\n " + (.getPath home-home) "and" (.getPath xdg-home)) + (warn-once "Using" (.getPath home-home) "for config.")) + (.getAbsolutePath (or (and explicit-home (io/file explicit-home)) + (existing-file home-home) + (existing-file xdg-home) + home-home)))) ;; TODO: move all these memoized fns into delays (def init diff --git a/leiningen-core/src/leiningen/core/utils.clj b/leiningen-core/src/leiningen/core/utils.clj index afe28a01d..eb9c94e35 100644 --- a/leiningen-core/src/leiningen/core/utils.clj +++ b/leiningen-core/src/leiningen/core/utils.clj @@ -6,7 +6,20 @@ (clojure.lang LineNumberingPushbackReader) (java.io ByteArrayOutputStream PrintStream File FileDescriptor FileOutputStream FileInputStream InputStreamReader) - (java.net URL))) + (java.net URL) + (java.nio.file Files) + (java.nio.file.attribute PosixFilePermissions))) + +(defn create-tmpdir + "Creates a temporary directory in parent (something clojure.java.io/as-path + can handle) with the specified permissions string (something + PosixFilePermissions/asFileAttribute can handle i.e. \"rw-------\") and + returns its Path." + [parent prefix permissions] + (let [nio-path (.toPath (io/as-file parent)) + perms (PosixFilePermissions/fromString permissions) + attr (PosixFilePermissions/asFileAttribute perms)] + (Files/createTempDirectory nio-path prefix (into-array [attr])))) (def rebound-io? (atom false)) @@ -20,7 +33,7 @@ (defn build-url "Creates java.net.URL from string" - [url] + ^URL [url] (try (URL. url) (catch java.net.MalformedURLException _ (URL. (str "http://" url))))) diff --git a/leiningen-core/test/leiningen/core/test/classpath.clj b/leiningen-core/test/leiningen/core/test/classpath.clj index bbf180359..73bb9b021 100644 --- a/leiningen-core/test/leiningen/core/test/classpath.clj +++ b/leiningen-core/test/leiningen/core/test/classpath.clj @@ -50,12 +50,14 @@ (catch Exception e (stacktrace/root-cause e)))))) (testing "checks for host of cert" - (is (instance? javax.net.ssl.SSLPeerUnverifiedException - (try - (binding [main/*info* false] - (resolve-with-repo "https://badssl.f5n.de/")) - (catch Exception e - (stacktrace/root-cause e)))))) + (let [ex (try + (binding [main/*info* false] + (resolve-with-repo "https://badssl.f5n.de/")) + (catch Exception e + (stacktrace/root-cause e)))] + (is (or (instance? javax.net.ssl.SSLException ex) + (instance? javax.net.ssl.SSLPeerUnverifiedException ex) + (instance? java.security.GeneralSecurityException ex))))) (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") @@ -165,16 +167,16 @@ {#"clojars" {:username "flynn" :password "flotilla"}}}})] - (is (= [["clojars" {:url "http://clojars.org/repo" + (is (= [["clojars" {:url "https://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}]]))))) + (map add-repo-auth + [["clojars" {:url "https://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" diff --git a/leiningen-core/test/leiningen/core/test/eval.clj b/leiningen-core/test/leiningen/core/test/eval.clj index e916b6041..24d79f44b 100644 --- a/leiningen-core/test/leiningen/core/test/eval.clj +++ b/leiningen-core/test/leiningen/core/test/eval.clj @@ -2,7 +2,6 @@ (: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]) @@ -95,3 +94,13 @@ (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"))))) + +(deftest preserve-eval-meta + (let [project (assoc project :eval-in :pprint) + form `(do (defn ~'str-bytes [^String s#] (.getBytes s#))) + tagged-arg #"\^java.lang.String s"] + (is (not (re-find tagged-arg (with-out-str + (eval-in-project project form))))) + + (is (re-find tagged-arg (with-out-str + (eval-in-project (assoc project :preserve-eval-meta true) form)))))) diff --git a/leiningen-core/test/leiningen/core/test/pedantic.clj b/leiningen-core/test/leiningen/core/test/pedantic.clj index 8f520f1bf..b02b5d981 100644 --- a/leiningen-core/test/leiningen/core/test/pedantic.clj +++ b/leiningen-core/test/leiningen/core/test/pedantic.clj @@ -1,12 +1,15 @@ (ns leiningen.core.test.pedantic (:require [clojure.test :refer :all] [clojure.java.io :as io] + [leiningen.core.classpath :as cp] [leiningen.core.pedantic :as pedantic] - [cemerick.pomegranate.aether :as aether])) + [cemerick.pomegranate.aether :as aether]) + (:import (org.eclipse.aether.graph DependencyNode))) (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) @@ -87,19 +90,11 @@ (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] +(defn resolve-deps [ranges overrides coords] (aether/resolve-dependencies :coordinates coords :repositories {"test-repo" {:url "fake://ss" - :checksum false}} + :checksum :warn}} :local-repo tmp-local-repo-dir :repository-session-fn #(-> % @@ -112,16 +107,29 @@ (defmethod translate java.util.List [l] - (remove nil? (map translate l))) + (vec (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 +(defn- node->artifact-map + [^DependencyNode 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)))))) + +(defmethod translate DependencyNode [n] - (if-let [a (#'pedantic/node->artifact-map n)] - [(symbol (:artifactId a)) (:version a)])) + (if-let [a (node->artifact-map n)] + [(if (= (:groupId a) (:artifactId a)) + (symbol (:artifactId a)) + (symbol (:groupId a) (:artifactId a))) + (:version a)])) (def repo '{[a "1"] [] @@ -131,41 +139,89 @@ [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 []}]))) + (let [ranges (atom []) + overrides (atom [])] + (resolve-deps ranges overrides + '[[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 - []))) + (let [ranges (atom []) + overrides (atom [])] + (resolve-deps ranges overrides '[[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"]]}]}]))) - + (let [ranges (atom []) + overrides (atom [])] + (resolve-deps ranges overrides '[[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 []}])))) + +(deftest netty-boringssl-works + (let [project {:root "/tmp" + :dependencies '[[io.netty/netty-tcnative-boringssl-static + "2.0.50.Final"]] + :pedantic? :warn + :repositories [["c" {:url "https://repo1.maven.org/maven2/" + :snapshots false}]]}] + ;; this will result in an infinite loop in lein 2.9.8 + (is (cp/get-classpath project)))) + +(deftest ^:online multiple-paths-to-ignored-dep + (let [ranges (atom []) + overrides (atom [])] + (aether/resolve-dependencies + :coordinates '[[com.amazonaws/aws-java-sdk-s3 "1.12.402"]] + :repository-session-fn + #(-> % + aether/repository-session + (#'pedantic/use-transformer ranges overrides))) + + (is (empty? @ranges)) + (is (= (translate @overrides) + '[{:accepted {:node [commons-logging "1.1.3"] + :parents [[com.amazonaws/aws-java-sdk-s3 "1.12.402"] + [com.amazonaws/aws-java-sdk-core "1.12.402"]]} + :ignoreds [; leiningen <= 2.10 used to also report this path, + ; now we only report the shortest path + #_{:node [commons-logging "1.2"] + :parents [[com.amazonaws/aws-java-sdk-s3 "1.12.402"] + [com.amazonaws/aws-java-sdk-kms "1.12.402"] + [com.amazonaws/aws-java-sdk-core "1.12.402"] + [org.apache.httpcomponents/httpclient "4.5.13"]]} + {:node [commons-logging "1.2"] + :parents [[com.amazonaws/aws-java-sdk-s3 "1.12.402"] + [com.amazonaws/aws-java-sdk-core "1.12.402"] + [org.apache.httpcomponents/httpclient "4.5.13"]]}] + :ranges []}])))) + +(deftest dont-suggest-on-duplicates + (let [project {:root "/tmp" + :repositories [["c" {:url "https://repo1.maven.org/maven2/" + :snapshots false}]] + :dependencies '[[commons-logging "1.2"] + [commons-logging "1.2"]] + :pedantic? :abort}] + (is (cp/get-dependencies :dependencies nil project)))) diff --git a/leiningen-core/test/leiningen/core/test/project.clj b/leiningen-core/test/leiningen/core/test/project.clj index cec64dec1..a1f3f1680 100755 --- a/leiningen-core/test/leiningen/core/test/project.clj +++ b/leiningen-core/test/leiningen/core/test/project.clj @@ -6,6 +6,7 @@ [leiningen.core.test.helper :refer [abort-msg]] [leiningen.test.helper :as lthelper] [leiningen.core.utils :as utils] + [leiningen.core.main :as main] [clojure.java.io :as io]) (:import (java.io StringReader))) @@ -44,7 +45,7 @@ [stencil/stencil "0.2.0"] [~(symbol "net.3scale" "3scale-api") "3.0.2"] [clj-http/clj-http "3.4.1"] - [nrepl/nrepl "0.9.0" + [nrepl/nrepl "1.0.0" :exclusions [[org.clojure/clojure]]] [org.nrepl/incomplete "0.1.0" :exclusions [[org.clojure/clojure]]]], @@ -409,7 +410,8 @@ (deftest test-global-exclusions (let [project {:dependencies - '[[lancet "1.0.1"] + '[[org.clojure/clojure "1.11.1"] + [lancet "1.0.1"] [leiningen-core "2.0.0-SNAPSHOT" :exclusions [pomegranate]] [clucy "0.2.2" :exclusions [org.clojure/clojure]]] :exclusions '[org.clojure/clojure]} @@ -417,7 +419,11 @@ (is (= '[[[org.clojure/clojure]] [[org.clojure/clojure] [pomegranate/pomegranate]] [[org.clojure/clojure]]] - (map #(distinct (:exclusions (apply hash-map %))) dependencies))))) + (map #(distinct (:exclusions (apply hash-map %))) dependencies))) + (is (= '[[lancet/lancet "1.0.1" :exclusions ([org.clojure/clojure])] + [leiningen-core/leiningen-core "2.0.0-SNAPSHOT" :exclusions ([org.clojure/clojure] [pomegranate/pomegranate])] + [clucy/clucy "0.2.2" :exclusions ([org.clojure/clojure])]] + dependencies)))) (defn add-seven [project] (assoc project :seven 7)) @@ -489,14 +495,15 @@ (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))))) + (binding [main/*info* false] + (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-profiles-default-meta (is (= [:repl] @@ -545,17 +552,25 @@ :foo [:b]}}) (merge-profiles [:a :b :c]) (unmerge-profiles [:foo]) - (dissoc :profiles)))))) + (dissoc :profiles)))) + (testing "unmerge composite profiles" + (with-redefs [warn-once (fn [& _] (throw (Exception. "no warning!")))] + (let [project (project/init-project + (make-project {:profiles {:dev [:project/dev] + :project/dev {:dev? true}} + :dev? false}) + [:default])] + (is (not (:dev? (project/unmerge-profiles project [:dev]))))))))) (deftest test-merge-coll-with-metadata - (let [project - (-> (make-project - {:profiles - {:shared {:clean-targets ^{:protect false} ["resources/a.txt"]} - :prod [:shared {:clean-targets ^{:protect false} ["resources/b.txt"]}]}}) - (merge-profiles [:prod]))] - (is (= (:clean-targets project) ["resources/a.txt" "resources/b.txt"])) - (is (false? (-> project :clean-targets meta :protect))))) + (binding [main/*info* false] + (let [profiles {:shared {:clean-targets ^{:protect false} ["resources/a.txt"]} + :prod [:shared {:clean-targets + ^{:protect false} ["resources/b.txt"]}]} + project (-> (make-project {:profiles profiles}) + (merge-profiles [:prod]))] + (is (= (:clean-targets project) ["resources/a.txt" "resources/b.txt"])) + (is (false? (-> project :clean-targets meta :protect)))))) (deftest test-dedupe-deps (is (= '[[org.clojure/clojure "1.3.0"] @@ -663,5 +678,15 @@ result (unmerge-profiles project [:system :base :provided :user])] (is (= '[[org.clojure/clojure "1.10.1"] [ring "1.8.2" :scope "test"]] - (:dependencies result))))) - + (:dependencies result))) + ;; Even though this isn't a part of the formal API, ensure + ;; that unmerging correctly adjust :active-profiles too. + (is (= [:ring] (-> result meta :active-profiles))))) + +(deftest test-target-path + (let [project (init-project {:dependencies '[[org.clojure/clojure "1.10.1"]] + :target-path "target/%s" + :profiles {:uberjar {}}} + [:default]) + project (merge-profiles project [:uberjar])] + (is (= "target/uberjar" (:target-path project))))) diff --git a/pcmpl-lein.el b/pcmpl-lein.el index d012aa6e3..1d3dcfd8d 100644 --- a/pcmpl-lein.el +++ b/pcmpl-lein.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2011 Phil Hagelberg ;; ;; Author: Phil Hagelberg -;; URL: http://github.com/technomancy/leiningen +;; URL: https://github.com/technomancy/leiningen ;; Version: 0.1 ;; Keywords: eshell completion ;; Created: 2011-01-15 diff --git a/project.clj b/project.clj index 9a3769f15..20692c7f0 100644 --- a/project.clj +++ b/project.clj @@ -1,39 +1,33 @@ ;; 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.9-SNAPSHOT" +(defproject leiningen "2.11.3-SNAPSHOT" :description "Automate Clojure projects without setting your hair on fire." - :url "https://github.com/technomancy/leiningen" + :url "https://codeberg.org/leiningen/leiningen" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} ;; If you update these, update resources/leiningen/bootclasspath-deps.clj too - :dependencies [[leiningen-core "2.9.9-SNAPSHOT"] + :dependencies [[leiningen-core "2.11.3-SNAPSHOT"] ;; needed for pom [org.clojure/data.xml "0.2.0-alpha6"] ;; needed for test [timofreiberg/bultitude "0.3.0" - :exclusions [org.clojure/clojure]] + :exclusions [org.clojure/clojure + org.tcrawley/dynapath]] ;; needed for new [stencil "0.5.0" :exclusions [org.clojure/core.cache]] ;; needed for uberjar [commons-lang "2.6"] ;; needed for repl - [nrepl "0.9.0"] + [nrepl "1.3.0"] ;; needed for change - [org.clojars.trptcolin/sjacket "0.1.1.1" :exclusions [org.clojure/clojure]] + [org.clojars.trptcolin/sjacket "0.1.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.8.0"] - [org.apache.httpcomponents/httpclient "4.5.13"] - ;; for PRISMA-2021-0055, dep: org.apache.httpcomponents/httpclient (patched above), - ;; which hasn't bumped commons-codec in its most recent version. - [commons-codec "1.15"] - [org.apache.httpcomponents/httpcore "4.4.13"] - ;; for CVE-2021-37714, dep chain: leiningen-core -> clj-commons/pomegranate -> - ;; org.apache.maven.wagon/wagon-http -> org.apache.maven.wagon/wagon-http-shared -> - ;; -> org.jsoup/jsoup - [org.jsoup/jsoup "1.14.2"]] + [commons-codec "1.15"]] :pedantic? :abort ;; checkout-deps don't work with :eval-in :leiningen :profiles {:dev {:resource-paths ["leiningen-core/dev-resources"] @@ -41,7 +35,12 @@ :uberjar {:aot [#"leiningen" leiningen.core.ssl ; lazy-loaded cemerick.pomegranate + cemerick.pomegranate.aether classlojure.core + dynapath.dynamic-classpath + dynapath.defaults + dynapath.util + bultitude.core nrepl.core]}} :test-selectors {:default (complement :disabled) :offline (comp (partial not-any? identity) diff --git a/resources/leiningen/bootclasspath-deps.clj b/resources/leiningen/bootclasspath-deps.clj index 901acda24..4d1949e1e 100644 --- a/resources/leiningen/bootclasspath-deps.clj +++ b/resources/leiningen/bootclasspath-deps.clj @@ -13,61 +13,74 @@ (let [hierarchy (cp/managed-dependency-hierarchy :dependencies :managed-dependencies (project/read))] - (-> (into {} (for [[a v] (artifacts hierarchy)] - [a v])) + (-> (into (sorted-map-by (fn [x y] + (compare (str x) (str y)))) + (for [[a v] (artifacts hierarchy)] + [a v])) ;; Unhelpful to warn on these: (dissoc 'org.clojure/clojure) (dissoc 'leiningen-core) (pp/pprint)))) -{ - clj-commons/pomegranate "1.2.1", - com.hypirion/io "0.3.1" +{clj-commons/pomegranate "1.2.24", + com.hypirion/io "0.3.1", + com.jcraft/jsch "0.1.55", + com.jcraft/jsch.agentproxy.connector-factory "0.0.9", + com.jcraft/jsch.agentproxy.core "0.0.9", + com.jcraft/jsch.agentproxy.jsch "0.0.9", + com.jcraft/jsch.agentproxy.pageant "0.0.9", + com.jcraft/jsch.agentproxy.sshagent "0.0.9", + com.jcraft/jsch.agentproxy.usocket-jna "0.0.9", + com.jcraft/jsch.agentproxy.usocket-nc "0.0.9", commons-codec "1.15", commons-io "2.8.0", commons-lang "2.6", - commons-logging "1.2", javax.inject "1", net.cgrand/parsley "0.9.3", net.cgrand/regex "1.1.0", - nrepl "0.9.0", - org.apache.commons/commons-lang3 "3.8.1", - org.apache.httpcomponents/httpclient "4.5.13", - org.apache.httpcomponents/httpcore "4.4.13", - org.apache.maven.resolver/maven-resolver-api "1.3.3", - org.apache.maven.resolver/maven-resolver-connector-basic "1.3.3", - org.apache.maven.resolver/maven-resolver-impl "1.3.3", - org.apache.maven.resolver/maven-resolver-spi "1.3.3", - org.apache.maven.resolver/maven-resolver-transport-file "1.3.3", - org.apache.maven.resolver/maven-resolver-transport-http "1.3.3", - org.apache.maven.resolver/maven-resolver-transport-wagon "1.3.3", - org.apache.maven.resolver/maven-resolver-util "1.3.3", - org.apache.maven.wagon/wagon-http "3.3.4", - org.apache.maven.wagon/wagon-http-shared "3.3.4", - org.apache.maven.wagon/wagon-provider-api "3.3.4", - org.apache.maven/maven-artifact "3.6.1", - org.apache.maven/maven-builder-support "3.6.1", - org.apache.maven/maven-model "3.6.1", - org.apache.maven/maven-model-builder "3.6.1", - org.apache.maven/maven-repository-metadata "3.6.1", - org.apache.maven/maven-resolver-provider "3.6.1", + net.java.dev.jna/jna "4.1.0", + net.java.dev.jna/jna-platform "4.1.0", + nrepl "1.3.0", + org.apache.commons/commons-lang3 "3.12.0", + org.apache.httpcomponents/httpclient "4.5.14", + org.apache.httpcomponents/httpcore "4.4.16", + org.apache.maven.resolver/maven-resolver-api "1.9.4", + org.apache.maven.resolver/maven-resolver-connector-basic "1.9.4", + org.apache.maven.resolver/maven-resolver-impl "1.9.4", + org.apache.maven.resolver/maven-resolver-named-locks "1.9.4", + org.apache.maven.resolver/maven-resolver-spi "1.9.4", + org.apache.maven.resolver/maven-resolver-transport-file "1.9.4", + org.apache.maven.resolver/maven-resolver-transport-http "1.9.4", + org.apache.maven.resolver/maven-resolver-transport-wagon "1.9.4", + org.apache.maven.resolver/maven-resolver-util "1.9.4", + org.apache.maven.wagon/wagon-http "3.5.3", + org.apache.maven.wagon/wagon-http-shared "3.5.3", + org.apache.maven.wagon/wagon-provider-api "3.5.3", + org.apache.maven.wagon/wagon-ssh "3.5.3", + org.apache.maven.wagon/wagon-ssh-common "3.5.3", + org.apache.maven/maven-artifact "3.8.7", + org.apache.maven/maven-builder-support "3.8.7", + org.apache.maven/maven-model "3.8.7", + org.apache.maven/maven-model-builder "3.8.7", + org.apache.maven/maven-repository-metadata "3.8.7", + org.apache.maven/maven-resolver-provider "3.8.7", org.clojars.trptcolin/sjacket "0.1.1.1", - org.clojure/core.specs.alpha "0.2.56", + org.clojure/core.specs.alpha "0.2.62", org.clojure/data.codec "0.1.0", - org.clojure/data.xml "0.2.0-alpha5", - org.clojure/spec.alpha "0.2.194", + org.clojure/data.xml "0.2.0-alpha6", + org.clojure/spec.alpha "0.3.218", org.clojure/tools.macro "0.1.5", - org.codehaus.plexus/plexus-interpolation "1.25", - org.codehaus.plexus/plexus-utils "3.2.0", + org.codehaus.plexus/plexus-interactivity-api "1.1", + org.codehaus.plexus/plexus-interpolation "1.26", + org.codehaus.plexus/plexus-utils "3.3.1", + org.eclipse.sisu/org.eclipse.sisu.inject "0.3.5", org.flatland/classlojure "0.7.1", - org.jsoup/jsoup "1.14.2", org.nrepl/incomplete "0.1.0", + org.slf4j/jcl-over-slf4j "1.7.36", org.slf4j/slf4j-api "1.7.25", org.slf4j/slf4j-nop "1.7.25", - org.tcrawley/dynapath "1.0.0", + org.tcrawley/dynapath "1.1.0", quoin "0.1.2", robert/hooke "1.3.0", scout "0.1.1", stencil "0.5.0", - timofreiberg/bultitude "0.3.0", - org.codehaus.plexus/plexus-component-annotations "1.7.1", - } + timofreiberg/bultitude "0.3.0"} diff --git a/resources/leiningen/new/app/CHANGELOG.md b/resources/leiningen/new/app/CHANGELOG.md index c3502edbd..ef7dd92e5 100644 --- a/resources/leiningen/new/app/CHANGELOG.md +++ b/resources/leiningen/new/app/CHANGELOG.md @@ -1,5 +1,5 @@ # 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/). +All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](https://keepachangelog.com/). ## [Unreleased] ### Changed diff --git a/resources/leiningen/new/app/README.md b/resources/leiningen/new/app/README.md index d1452d7e3..99c572822 100644 --- a/resources/leiningen/new/app/README.md +++ b/resources/leiningen/new/app/README.md @@ -4,7 +4,7 @@ FIXME: description ## Installation -Download from http://example.com/FIXME. +Download from https://example.com/FIXME. ## Usage @@ -34,7 +34,7 @@ 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. +https://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 diff --git a/resources/leiningen/new/app/intro.md b/resources/leiningen/new/app/intro.md index 3b6a3e841..ccf9ca8a3 100644 --- a/resources/leiningen/new/app/intro.md +++ b/resources/leiningen/new/app/intro.md @@ -1,3 +1,3 @@ # Introduction to {{name}} -TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) +TODO: write [great documentation](https://jacobian.org/writing/what-to-write/) diff --git a/resources/leiningen/new/app/project.clj b/resources/leiningen/new/app/project.clj index 714d8640f..be88aeccc 100644 --- a/resources/leiningen/new/app/project.clj +++ b/resources/leiningen/new/app/project.clj @@ -1,6 +1,6 @@ (defproject {{raw-name}} "0.1.0-SNAPSHOT" :description "FIXME: write description" - :url "http://example.com/FIXME" + :url "https://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.11.1"]] diff --git a/resources/leiningen/new/default/CHANGELOG.md b/resources/leiningen/new/default/CHANGELOG.md index c3502edbd..ef7dd92e5 100644 --- a/resources/leiningen/new/default/CHANGELOG.md +++ b/resources/leiningen/new/default/CHANGELOG.md @@ -1,5 +1,5 @@ # 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/). +All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](https://keepachangelog.com/). ## [Unreleased] ### Changed diff --git a/resources/leiningen/new/default/README.md b/resources/leiningen/new/default/README.md index d99c7d481..faccfae88 100644 --- a/resources/leiningen/new/default/README.md +++ b/resources/leiningen/new/default/README.md @@ -12,7 +12,7 @@ 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. +https://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 diff --git a/resources/leiningen/new/default/intro.md b/resources/leiningen/new/default/intro.md index 3b6a3e841..ccf9ca8a3 100644 --- a/resources/leiningen/new/default/intro.md +++ b/resources/leiningen/new/default/intro.md @@ -1,3 +1,3 @@ # Introduction to {{name}} -TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) +TODO: write [great documentation](https://jacobian.org/writing/what-to-write/) diff --git a/resources/leiningen/new/default/project.clj b/resources/leiningen/new/default/project.clj index a18d156c8..271cedd18 100644 --- a/resources/leiningen/new/default/project.clj +++ b/resources/leiningen/new/default/project.clj @@ -1,6 +1,6 @@ (defproject {{raw-name}} "0.1.0-SNAPSHOT" :description "FIXME: write description" - :url "http://example.com/FIXME" + :url "https://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.11.1"]] diff --git a/resources/leiningen/new/plugin/CHANGELOG.md b/resources/leiningen/new/plugin/CHANGELOG.md index c3502edbd..ef7dd92e5 100644 --- a/resources/leiningen/new/plugin/CHANGELOG.md +++ b/resources/leiningen/new/plugin/CHANGELOG.md @@ -1,5 +1,5 @@ # 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/). +All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](https://keepachangelog.com/). ## [Unreleased] ### Changed diff --git a/resources/leiningen/new/plugin/README.md b/resources/leiningen/new/plugin/README.md index 7381b2328..88ed5f7a6 100644 --- a/resources/leiningen/new/plugin/README.md +++ b/resources/leiningen/new/plugin/README.md @@ -23,7 +23,7 @@ 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. +https://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 diff --git a/resources/leiningen/new/plugin/project.clj b/resources/leiningen/new/plugin/project.clj index fe484c53f..cc33eb56b 100644 --- a/resources/leiningen/new/plugin/project.clj +++ b/resources/leiningen/new/plugin/project.clj @@ -1,6 +1,6 @@ (defproject {{name}} "0.1.0-SNAPSHOT" :description "FIXME: write description" - :url "http://example.com/FIXME" + :url "https://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) diff --git a/resources/leiningen/new/template/CHANGELOG.md b/resources/leiningen/new/template/CHANGELOG.md index 3ca642503..d10cad916 100644 --- a/resources/leiningen/new/template/CHANGELOG.md +++ b/resources/leiningen/new/template/CHANGELOG.md @@ -1,5 +1,5 @@ # 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/). +All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](https://keepachangelog.com/). ## [Unreleased] ### Changed diff --git a/resources/leiningen/new/template/README.md b/resources/leiningen/new/template/README.md index b5b29411e..c51aef3b3 100644 --- a/resources/leiningen/new/template/README.md +++ b/resources/leiningen/new/template/README.md @@ -12,7 +12,7 @@ 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. +https://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 diff --git a/resources/leiningen/new/template/project.clj b/resources/leiningen/new/template/project.clj index e7f55a97e..9999a009e 100644 --- a/resources/leiningen/new/template/project.clj +++ b/resources/leiningen/new/template/project.clj @@ -1,6 +1,6 @@ (defproject {{group-prefix}}lein-template.{{artifact-id}} "0.1.0-SNAPSHOT" :description "FIXME: write description" - :url "http://example.com/FIXME" + :url "https://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) diff --git a/sample.project.clj b/sample.project.clj index 6404be22e..cf1bb85bd 100644 --- a/sample.project.clj +++ b/sample.project.clj @@ -14,14 +14,14 @@ ;;; Project Metadata ;; The description text is searchable from repositories like Clojars. :description "A sample project" - :url "http://example.org/sample-clojure-project" + :url "https://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"] + :archive "https://example.org/sample-mailing-list-archives" + :other-archives ["https://example.org/sample-list-archive2" + "https://example.org/sample-list-archive3"] :post "list@example.org" :subscribe "list-subscribe@example.org" :unsubscribe "list-unsubscribe@example.org"} @@ -29,7 +29,7 @@ ;; :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" + :url "https://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 @@ -47,7 +47,7 @@ ;; 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 + ;; You can also use 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"] @@ -131,15 +131,15 @@ ;; 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"]] + :plugin-repositories [["internal-plugin-repo" "https://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"} + :url "https://mirrors.ibiblio.org/pub/mirrors/maven2"} #"clojars" {:name "Internal nexus" - :url "http://mvn.local/nexus/releases" + :url "https://mvn.local/nexus/releases" :repo-manager true}} ;; Override location of the local maven repository. Relative to project root. :local-repo "local-m2" @@ -154,7 +154,7 @@ ;; 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" + :deploy-repositories [["releases" {:url "https://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 @@ -163,9 +163,15 @@ ;; Currently only works in :deploy-repositories ;; or as a top-level (global) setting. :signing {:gpg-key "0xAB123456"}}] - ["snapshots" "http://blueant.com/archiva/internal/snapshots"]] + ["snapshots" "https://blueant.com/archiva/internal/snapshots"]] ;; Defaults for signing options. Defers to per-repository settings. - :signing {:gpg-key "root@eruditorum.org"} + ;; You can set this in the :user profile in ~/.lein/profiles.clj too. + :signing {;; specify which key to use for signing; set to false to disable. + ;; defaults to using whatever key GPG is configured to use. + :gpg-key "root@eruditorum.org" + ;; specify which SSH key to use for signing; defaults to not signing + ;; with SSH. + :ssh-key "~/.ssh/id_rsa"} ;; 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. @@ -273,7 +279,7 @@ ;; with certain uses of protocols and records. :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 + ;; Allows working around the Gilardi Scenario: https://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 @@ -290,6 +296,9 @@ ;; valid global variables to set (and their meaningful values). :global-vars {*warn-on-reflection* true *assert* false} + ;; Preserve metadata when evaluating project code. This can remove reflection + ;; warnings but can also cause incompatibilities with certain plugins. + :preserve-eval-meta true ;; 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" @@ -341,7 +350,7 @@ ;; 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 + ;; Workaround for https://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 @@ -382,9 +391,20 @@ ;; 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 + ;; attaches to. Specify either a filesystem :socket + ;; (where the parent directory should be used to + ;; control access since POSIX doesn't require + ;; respecting the socket permissions): + :socket "/path/to/the/socket" + ;; or a network :host and/or :port + ;; :host "0.0.0.0" + ;; :port 4001 + ;; File name to use as history: user input will be stored there + ;; over sessions. Defaults to .lein-repl-history inside a + ;; project or to repl-history in the Leiningen home directory + ;; outside of a project. Use nil (or file name like + ;; "/dev/null") to disable REPL history completely. + :history-file "/tmp/my-project-repl-history" ;; If nREPL takes too long to load it may timeout, ;; increase this to wait longer before timing out. ;; Defaults to 30000 (30 seconds) @@ -508,7 +528,7 @@ [:role "maintainer"]]]] [:contributors [:contributor [:name "Ben Bitdiddle"] - [:url "http://www.example.com/benjamin"] + [:url "https://www.example.com/benjamin"] [:properties [:id "benbit"]]]]) ;;; Safety flags @@ -520,7 +540,7 @@ ;; 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"] + :deploy-branches ["main"] ;;; Artifact Classifers Installation ;; Option to install classified maven artifacts. A map where keys diff --git a/src/leiningen/check.clj b/src/leiningen/check.clj index 13416fa03..3aae87ed5 100644 --- a/src/leiningen/check.clj +++ b/src/leiningen/check.clj @@ -18,7 +18,7 @@ (.replace \- \_) (.replace \. \/))] (binding [*out* *err*] - (println "Compiling namespace" ns#)) + (println "Checking namespace" ns#)) (try (binding [*warn-on-reflection* true] (load ns-file#)) @@ -27,9 +27,9 @@ (.printStackTrace e#))))) (if-not (zero? @failures#) (System/exit @failures#))) - project (assoc project - :aot nil - :target-path (str (:target-path project) "/check"))] + project (assoc-in project [:global-vars '*warn-on-reflection*] true) + project (assoc project :target-path + (str (:target-path project) "/check"))] (try (binding [eval/*pump-in* false] (eval/eval-in-project project action)) diff --git a/src/leiningen/classpath.clj b/src/leiningen/classpath.clj index 0a821f8e9..6d974746f 100644 --- a/src/leiningen/classpath.clj +++ b/src/leiningen/classpath.clj @@ -2,13 +2,12 @@ "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))) + [clojure.string :as str])) (defn get-classpath-string [project] (try (str/join java.io.File/pathSeparatorChar (classpath/get-classpath project)) - (catch DependencyResolutionException e + (catch Exception e (main/abort (.getMessage e))))) (defn classpath diff --git a/src/leiningen/deploy.clj b/src/leiningen/deploy.clj index 8b1b54f0e..e339cd815 100644 --- a/src/leiningen/deploy.clj +++ b/src/leiningen/deploy.clj @@ -29,6 +29,12 @@ [id (assoc settings :username username :password password)] [id settings]))) +;; for some reason they nerfed Console so you can't use proxy with it, +;; so we gotta do this the dipshit way to make it testable. +(defn read-password-fn [] + (if (System/console) + #(.readPassword (System/console) "%s" (into-array [%])))) + (defn add-auth-interactively [[id settings]] (if (or (and (:username settings) (some settings [:password :passphrase :private-key-file])) @@ -49,9 +55,9 @@ "to avoid prompts.") (print "Username: ") (flush) (let [username (read-line) - console (System/console) - password (if console - (.readPassword console "%s" (into-array ["Password: "])) + read-password (read-password-fn) + password (if read-password + (apply str (read-password "Password: ")) (do (println "LEIN IS UNABLE TO TURN OFF ECHOING, SO" "THE PASSWORD IS PRINTED TO THE CONSOLE") @@ -93,23 +99,40 @@ "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- ssh-keygen-cmd [file opts] + ["ssh-keygen" "-Y" "sign" "-f" (:ssh-key opts) "-n" "file" file]) + +(defn- sign-ssh [file opts] + (when-not (zero? (apply eval/sh (ssh-keygen-cmd file opts))) + (main/abort "Could not sign" file)) + (str file ".sig")) + +(defn- signature-filename [coords extension] + (apply concat (update-in (apply hash-map coords) [:extension] + #(str (or % "jar") extension)))) + +(defn- gpg-signature-for-artifact [[coords artifact-file] opts] + (if (not= false (:gpg-key opts)) + {(signature-filename coords ".asc") (sign artifact-file opts)})) + +(defn- ssh-signature-for-artifact [[coords artifact-file] opts] + (if (:ssh-key opts) + {(signature-filename coords ".sig") (sign-ssh artifact-file opts)})) + +(defn signature-for-artifact [artifact opts] + (merge (gpg-signature-for-artifact artifact opts) + (ssh-signature-for-artifact artifact 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") + (println "Need to sign" total "files") (doall (map-indexed (fn [idx [coords artifact-file :as artifact]] - (printf "[%d/%d] Signing %s with GPG\n" (inc idx) total artifact-file) + (printf "[%d/%d] Signing %s\n" (inc idx) total artifact-file) (flush) (signature-for-artifact artifact sig-opts)) artifacts)))) @@ -138,7 +161,7 @@ (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.")))) + (main/warn ";; WARNING: please set" key "in project.clj.")))) (defn- in-branches [branches] (-> (sh/sh "git" "rev-parse" "--abbrev-ref" "HEAD") @@ -158,7 +181,7 @@ (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 " + See https://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)] diff --git a/src/leiningen/deps.clj b/src/leiningen/deps.clj index 628165b8a..7967acd53 100644 --- a/src/leiningen/deps.clj +++ b/src/leiningen/deps.clj @@ -84,7 +84,8 @@ for." {":tree" [:dependencies :managed-dependencies] ":tree-data" [:dependencies :managed-dependencies] - ":plugin-tree" [:plugins nil]}) + ":plugin-tree" [:plugins nil] + ":plugin-tree-data" [:plugins nil]}) @@ -122,6 +123,10 @@ Show the full dependency tree as above, but in EDN format. Show the full dependency tree for the plugins in the current project. + lein deps :plugin-tree-data + +Show the full dependency tree for the plugins in the current project as above, but in EDN format. + lein deps :verify Check signatures of each dependency. ALPHA: subject to change. @@ -169,7 +174,9 @@ force them to be updated, use `lein -U $TASK`." ":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)))) + (pprint/pprint hierarchy)) + ":plugin-tree-data" (binding [*print-length* 10000 *print-level* 10000] + (pprint/pprint hierarchy)))) (= command ":verify") (if (user/gpg-available?) (walk-deps (classpath/managed-dependency-hierarchy diff --git a/src/leiningen/jar.clj b/src/leiningen/jar.clj index 9091394e3..a1925d4cc 100644 --- a/src/leiningen/jar.clj +++ b/src/leiningen/jar.clj @@ -237,15 +237,14 @@ "\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)))) +(defn warn-implicit-aot [project] + (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] @@ -268,7 +267,10 @@ [project main f & args] (-> (apply f project args) (project/retain-whitelisted-keys project) - (add-main main))) + (add-main main) + ;; Ensure test paths can't affect jar compilation + ;; https://github.com/technomancy/leiningen/issues/2808 + (assoc :test-paths []))) (defn- preprocess-project [project & [main]] (process-project project main project/unmerge-profiles @@ -305,7 +307,7 @@ 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.")) + ";; 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)))} @@ -342,7 +344,8 @@ With an argument, the jar will be built with an alternate main." default-profiles (set (project/expand-profile project :default)) provided-profiles (remove (set/difference default-profiles scoped-profiles) - (-> project meta :included-profiles)) + (->> project meta :included-profiles + (project/expand-profiles project))) project (preprocess-project project main)] (merge (main-jar project provided-profiles main) (classifier-jars project provided-profiles))))) diff --git a/src/leiningen/new.clj b/src/leiningen/new.clj index fd3b2aada..de4303e82 100644 --- a/src/leiningen/new.clj +++ b/src/leiningen/new.clj @@ -1,13 +1,16 @@ (ns leiningen.new "Generate project scaffolding based on a template." - (:refer-clojure :exclude [new list]) + (:refer-clojure :exclude [new]) (:require [clojure.string :as str] - [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 debug]] - [leiningen.new.templates :refer [*dir* *force?*]]) + [leiningen.new.templates :refer [*dir* *force?*]] + leiningen.new.template + leiningen.new.plugin + leiningen.new.default + leiningen.new.app) (:import java.io.FileNotFoundException)) (def ^:dynamic *use-snapshots?* false) @@ -36,7 +39,8 @@ project/default-repositories (:plugin-repositories user-profiles))] (merge {:templates [[(template-symbol name) template-version]] - :repositories repositories} + :repositories repositories + :update :always} (select-keys user-profiles [:mirrors])))) (defn resolve-remote-template [name ns-sym] @@ -51,7 +55,7 @@ (defn resolve-template [template-name] (let [ns-sym (symbol (str "leiningen.new." (name (symbol template-name))))] - (if (try (require ns-sym) + (if (try (require (symbol (str "leiningen.new." template-name))) true (catch FileNotFoundException _ (resolve-remote-template template-name ns-sym))) @@ -106,15 +110,6 @@ ;; 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] @@ -150,7 +145,10 @@ (defn ^{:no-project-needed true :help-arglists '[[project project-name] [project template project-name [-- & args]]] - :subtasks (list)} + :subtasks [#'leiningen.new.template/template + #'leiningen.new.plugin/plugin + #'leiningen.new.default/default + #'leiningen.new.app/app]} new "Generate scaffolding for a new project based on a template. diff --git a/src/leiningen/new/template.clj b/src/leiningen/new/template.clj index ae8431369..06867dde4 100644 --- a/src/leiningen/new/template.clj +++ b/src/leiningen/new/template.clj @@ -7,10 +7,10 @@ "A meta-template for 'lein new' templates." [template-name] (when-not (namespace (symbol template-name)) - (main/warn (str "Template names must use a group-id to conform with new" + (main/warn (str ";; Template names must use a group-id to conform with new" " Clojars security policy:\n" - "https://github.com/clojars/clojars-web/wiki/Verified-Group-Names" - "\n\nYou may generate this template but you may not be" + ";; https://github.com/clojars/clojars-web/wiki/Verified-Group-Names" + "\n\n;; You may generate this template but you may not be" " able to publish it on Clojars."))) (let [render (t/renderer "template") sym (symbol template-name) diff --git a/src/leiningen/plugin.clj b/src/leiningen/plugin.clj index 444fbc5e7..b9efc2c5f 100644 --- a/src/leiningen/plugin.clj +++ b/src/leiningen/plugin.clj @@ -5,7 +5,4 @@ (defn ^:no-project-needed plugin "DEPRECATED. Please use the :user profile instead." [& args] - (main/abort "The plugin task has been removed.\n" - "\nPlease see the upgrade guide for instructions on how to use" - "the user profile to\nspecify plugins instead:" - "https://github.com/technomancy/leiningen/wiki/Upgrading")) + (main/abort "The plugin task from Leiningen 1.x has been removed.")) diff --git a/src/leiningen/pom.clj b/src/leiningen/pom.clj index 3a9f346f3..65ea2b8df 100644 --- a/src/leiningen/pom.clj +++ b/src/leiningen/pom.clj @@ -12,7 +12,7 @@ [clojure.data.xml.name :as name] [leiningen.core.classpath :as classpath])) -(def pom-uri "http://maven.apache.org/POM/4.0.0") +(def pom-uri "https://maven.apache.org/POM/4.0.0") (def ^:private xsi-uri "http://www.w3.org/2001/XMLSchema-instance") @@ -110,7 +110,7 @@ "\n\n") + https://codeberg.org/leiningen/leiningen -->\n") (defn- camelize [string] (s/replace string #"[-_](\w)" (comp s/upper-case second))) @@ -363,7 +363,7 @@ [::pom/project {:xmlns pom-uri :xmlns/xsi xsi-uri ::xsi/schemaLocation - (str pom-uri " http://maven.apache.org/xsd/maven-4.0.0.xsd")} + (str pom-uri " https://maven.apache.org/xsd/maven-4.0.0.xsd")} [::pom/modelVersion "4.0.0"] (and (:parent project) (xml-tags :parent (:parent project))) [::pom/groupId (:group project)] diff --git a/src/leiningen/release.clj b/src/leiningen/release.clj index ed82dcad8..a194437c4 100644 --- a/src/leiningen/release.clj +++ b/src/leiningen/release.clj @@ -9,7 +9,7 @@ (defn string->semantic-version [version-string] "Create map representing the given version string. Returns nil if the string does not follow guidelines setforth by Semantic Versioning 2.0.0, - http://semver.org/" + https://semver.org/" ;; ..[-][-SNAPSHOT] (if-let [[_ major minor patch qualifier snapshot] (re-matches @@ -24,7 +24,7 @@ (defn parse-semantic-version [version-string] "Create map representing the given version string. Aborts with exit code 1 if the string does not follow guidelines setforth by Semantic Versioning 2.0.0, - http://semver.org/" + https://semver.org/" (or (string->semantic-version version-string) (main/abort "Unrecognized version string:" version-string))) @@ -141,7 +141,7 @@ bump. If none is given, it defaults to :patch." (when-let [[resource] (-> (.getContextClassLoader (Thread/currentThread)) (.getResources "leiningen/release.clj") (enumeration-seq) (distinct) (rest) (seq))] - (let [release-str (str resource)] + (let [release-str (slurp resource)] (when-not (re-find #"support existing release plugin" release-str) (clojure.lang.Compiler/load (io/reader resource) "leiningen/release.clj" release-str)))) diff --git a/src/leiningen/repl.clj b/src/leiningen/repl.clj index ac0f446aa..3461fc5e7 100644 --- a/src/leiningen/repl.clj +++ b/src/leiningen/repl.clj @@ -15,7 +15,10 @@ [leiningen.core.user :as user] [leiningen.core.project :as project] [leiningen.core.classpath :as classpath] - [leiningen.trampoline :as trampoline])) + [leiningen.trampoline :as trampoline]) + (:import + (java.io File) + (java.net URI))) (defn- repl-port-file-vector "Returns the repl port file for this project as a vector." @@ -39,6 +42,9 @@ (if-let [port (lookup-opt ":port" opts)] (Integer/valueOf port))) +(defn opt-socket [opts] + (lookup-opt ":socket" opts)) + (defn opt-transport [opts] (if-let [transport (lookup-opt ":transport" opts)] (utils/require-resolve transport))) @@ -53,18 +59,34 @@ (:ack-port nrepl.config/config))] (Integer/valueOf p))) -(defn repl-port [project] - (Integer/valueOf (or (user/getenv "LEIN_REPL_PORT") - (-> project :repl-options :port) - (:port nrepl.config/config) - 0))) - -(defn repl-host [project] - (or (user/getenv "LEIN_REPL_HOST") - (-> project :repl-options :host) - (:host nrepl.config/config) - (:bind nrepl.config/config) - "127.0.0.1")) +(defn configured-repl-connection [project opts] + (let [opt-host (lookup-opt ":host" opts) + opt-port (lookup-opt ":port" opts) + opt-sock (lookup-opt ":socket" opts) + env-host (user/getenv "LEIN_REPL_HOST") + env-port (user/getenv "LEIN_REPL_PORT") + env-sock (user/getenv "LEIN_REPL_SOCKET") + prj-host (-> project :repl-options :host) + prj-port (-> project :repl-options :port) + prj-sock (-> project :repl-options :socket) + nrepl-bind (nrepl.config/config :bind) + nrepl-host (nrepl.config/config :host) + nrepl-port (nrepl.config/config :port) + nrepl-sock (nrepl.config/config :socket)] + + (when (and opt-sock (or opt-host opt-port)) + (main/abort ":socket argument conflicts with :host and :port")) + (when (and env-sock (or env-host env-port)) + (main/abort "LEIN_REPL_HOST conflicts with LEIN_REPL_HOST and LEIN_REPL_PORT")) + (when (and prj-sock (or prj-host prj-port)) + (main/abort "project :repl-options :socket conflicts with :host and :port")) + (when (and nrepl-sock (or nrepl-bind nrepl-host nrepl-port)) + (main/abort "nREPL config :socket conflicts with :bind, :host, and :port")) + + (if-let [sock (or opt-sock env-sock prj-sock nrepl-sock)] + {:socket sock} + {:host (or opt-host env-host prj-host nrepl-host nrepl-bind "127.0.0.1") + :port (Integer/valueOf (or opt-port env-port prj-port nrepl-port 0))}))) (defn repl-transport [project] (if-let [transport (or (user/getenv "LEIN_REPL_TRANSPORT") @@ -78,15 +100,15 @@ (:greeting-fn nrepl.config/config))] (utils/require-resolve greeting-fn))) -(defn client-repl-port [project] - (let [port (repl-port project)] - (if (= port 0) +(defn client-repl-port [project configured-port] + (let [port configured-port] + (if (zero? configured-port) (try (-> (io/file (:root project) ".nrepl-port") slurp s/trim) (catch Exception _)) - port))) + configured-port))) (defn ensure-port [s] (if (re-find #":\d+($|/.*$)" s) @@ -108,17 +130,22 @@ false)) (defn connect-string [project opts] + ;; REVIEW: ignores command line :host ;port :socket, depending on the first arg? (let [opt (str (first opts))] (if-let [sx (string-from-file opt)] (connect-string project [sx]) (if (is-uri? opt) opt - (as-> (s/split opt #":") x - (remove s/blank? x) - (-> (drop-last (count x) [(repl-host project) (client-repl-port project)]) - (concat x)) - (s/join ":" x) - (ensure-port x)))))) + ;; TODO: perhaps use URI/toASCIIString (like nrepl, and server-forms) + (let [{:keys [host port socket]} (configured-repl-connection project opts)] + (when socket + (main/abort "Cannot connect to filesystem sockets yet")) + (as-> (s/split opt #":") x + (remove s/blank? x) + (-> (drop-last (count x) [host (client-repl-port project port)]) + (concat x)) + (s/join ":" x) + (ensure-port x))))))) (defn options-for-reply [project & {:keys [attach port scheme]}] (as-> (:repl-options project) opts @@ -208,26 +235,32 @@ (defn- server-forms [project cfg ack-port start-msg?] [`(do (if ~(some-> (:transport cfg) meta :ns str) (require (symbol ~(-> (:transport cfg) meta :ns str)))) - (let [server# (nrepl.server/start-server + (let [socket# ~(:socket cfg) + server# (nrepl.server/start-server :bind ~(:host cfg) :port ~(:port cfg) + :socket socket# :transport-fn ~(:transport cfg) :greeting-fn ~(:greeting-fn cfg) :ack-port ~ack-port - :handler ~(handler-for project)) - port# (:port server#) - repl-port-file# (apply io/file ~(repl-port-file-vector project)) - ;; TODO 3.0: remove legacy repl port support. - legacy-repl-port# (if (.exists (io/file ~(:target-path project ""))) - (io/file ~(:target-path project) "repl-port"))] - (when ~start-msg? - (println "nREPL server started on port" port# "on host" ~(:host cfg) - (str "- " - (transport/uri-scheme ~(or (:transport cfg) #'transport/bencode)) - "://" ~(:host cfg) ":" port#))) - (spit (doto repl-port-file# .deleteOnExit) port#) - (when legacy-repl-port# - (spit (doto legacy-repl-port# .deleteOnExit) port#)) + :handler ~(handler-for project))] + (if socket# + (when ~start-msg? + (println "nREPL server listening on " + (-> (URI. "nrepl+unix" socket# nil) .toASCIIString))) + (let [port# (:port server#) + repl-port-file# (apply io/file ~(repl-port-file-vector project)) + ;; TODO 3.0: remove legacy repl port support. + legacy-repl-port# (if (.exists (io/file ~(:target-path project ""))) + (io/file ~(:target-path project) "repl-port"))] + (when ~start-msg? + (println "nREPL server started on port" port# "on host" ~(:host cfg) + (str "- " + (transport/uri-scheme ~(or (:transport cfg) #'transport/bencode)) + "://" ~(:host cfg) ":" port#))) + (spit (doto ^File repl-port-file# .deleteOnExit) port#) + (when legacy-repl-port# + (spit (doto ^File legacy-repl-port# .deleteOnExit) port#)))) @(promise))) ;; TODO: remove in favour of :injections in the :repl profile `(do ~(when-let [init-ns (init-ns project)] @@ -253,6 +286,7 @@ (def reply-profile {:dependencies '[^:displace [reply "0.5.1" :exclusions [org.clojure/clojure ring/ring-core]] + ^:displace [net.cgrand/parsley "0.9.3" :exclusions [org.clojure/clojure]] [org.nrepl/incomplete "0.1.0"]]}) (defn- trampoline-repl [project port] @@ -275,7 +309,7 @@ "The server which handles ack replies." [transport] (nrepl.server/start-server - :bind (repl-host nil) + :bind (:nost (configured-repl-connection nil nil)) :handler (nrepl.ack/handle-ack nrepl.server/unknown-op) :transport-fn transport)) @@ -353,9 +387,16 @@ Subcommands: run under trampoline, the client/server step is skipped entirely; use the :headless command to start a trampolined server. -:headless [:host host] [:port port] - This will launch an nREPL server and wait, rather than connecting - a client to it. +:headless [[:host host] [:port port] | [:socket path]] + This will launch an nREPL server and wait (as per :start), without + connecting a client to it. If the :socket key is given, + LEIN_REPL_SOCKET is set, or :socket is present under :repl-options + in the project map, the server will listen on the filesystem socket + specified by the path. Note that POSIX does not specify the + effect (if any) of the socket file's permissions (and some systems + have ignored them), so any access control should be arranged via + parent directories. You may not specify both a socket and a + host/port. :connect [dest] Connects to an already running nREPL server. Dest can be: @@ -399,19 +440,24 @@ deactivated, but it can be overridden." (if (= subcommand ":connect") (client project (doto (connect-string project opts) (->> (main/info "Connecting to nREPL at")))) - (let [cfg {:host (or (opt-host opts) (repl-host project)) - :port (or (opt-port opts) (repl-port project)) - :transport (or (opt-transport opts) (repl-transport project)) - :greeting-fn (or (opt-greeting-fn opts) (repl-greeting-fn project))}] - (utils/with-write-permissions (repl-port-file-path project) - (case subcommand - ":start" (if trampoline/*trampoline?* - (trampoline-repl project (:port cfg)) - (client project (server project cfg false) cfg)) - ":headless" (apply eval/eval-in-project project - (server-forms project cfg (ack-port project) - true)) - (main/abort (str "Unknown subcommand " subcommand))))))))) + (let [cfg (assoc (configured-repl-connection project opts) + :transport (or (opt-transport opts) (repl-transport project)) + :greeting-fn (or (opt-greeting-fn opts) (repl-greeting-fn project))) + socket (:socket cfg) + run #(binding [eval/*eval-print-dup* true] + (case subcommand + ":start" (if trampoline/*trampoline?* + (trampoline-repl project (:port cfg)) + (client project (server project cfg false) cfg)) + ":headless" (apply eval/eval-in-project project + (server-forms project cfg + (when-not socket (ack-port project)) + true)) + (main/abort (str "Unknown subcommand " subcommand))))] + (if socket + (run) + (utils/with-write-permissions (repl-port-file-path project) + (run)))))))) ;; A note on testing the repl task: it has a number of modes of operation ;; which need to be tested individually: diff --git a/src/leiningen/run.clj b/src/leiningen/run.clj index b1d3c6420..33ebc64f4 100644 --- a/src/leiningen/run.clj +++ b/src/leiningen/run.clj @@ -76,8 +76,12 @@ ;; If the class exists, run its main method. class# + ;; NOTE: this prints a reflection warning, unless project has `:preserve-eval-meta true` + ;; https://github.com/technomancy/leiningen/issues/2695 + ;; https://github.com/technomancy/leiningen/issues/2328 + ; https://github.com/technomancy/leiningen/issues/2814 (Reflector/invokeStaticMethod - class# "main" (into-array [(into-array String '~args)])) + class# "main" ^"[Ljava.lang.Object;" (into-array [(into-array String '~args)])) ;; If the symbol didn't resolve, give a reasonable message (= :not-found ns-flag#) diff --git a/src/leiningen/search.clj b/src/leiningen/search.clj index ae70d24c8..67b517684 100644 --- a/src/leiningen/search.clj +++ b/src/leiningen/search.clj @@ -4,17 +4,27 @@ [clojure.xml :as xml] [leiningen.core.project :as project] [leiningen.core.main :as main]) - (:import (java.net URLEncoder))) + (:import (java.net URLEncoder) + (javax.xml.parsers SAXParser) + (org.xml.sax.helpers DefaultHandler))) (defn- decruft-central-xml [content] (zipmap (map #(get-in % [:attrs :name]) content) (map #(get-in % [:content 0]) content))) +;; replace clojure.xml version with one that doesn't do illegal access +(defn- startparse [^String url ^DefaultHandler ch] + (let [^SAXParser p (xml/disable-external-entities (xml/sax-parser))] + (.parse p url ch))) + (defn parse [url] - (try (xml/parse url) + (try (xml/parse url startparse) (catch Exception e - (main/warn "Could not retrieve search results from" url "because of" - (class e)) + (main/warn ";; Could not retrieve search results from" + (str url ":") + (if (re-find #"HTTP response code: (400|505)" (str e)) + "Query syntax unsupported." + (.getMessage e))) (when main/*debug* (.printStackTrace e))))) @@ -40,7 +50,7 @@ (defn ^:no-project-needed search "Search Central and Clojars for published artifacts." - [project query] + [project ^String query] (let [project (or project (project/make {})) repos (into {} (:repositories project))] (doseq [[repo searcher] [["central" search-central] @@ -50,6 +60,4 @@ (searcher (URLEncoder/encode query "UTF-8")) (catch java.io.IOException e (binding [*out* *err*] - (if (re-find #"HTTP response code: (400|505)" (str e)) - (println "Query syntax unsupported.") - (println "Remote error" (.getMessage e)))))))))) + (println "Query failed with message" (.getMessage e))))))))) diff --git a/src/leiningen/static_classpath.clj b/src/leiningen/static_classpath.clj new file mode 100644 index 000000000..6268a8dee --- /dev/null +++ b/src/leiningen/static_classpath.clj @@ -0,0 +1,40 @@ +(ns leiningen.static-classpath + "Print the classpath of the current project without loading code." + (:require [leiningen.classpath :as classpath] + [leiningen.core.project :as project] + [clojure.java.io :as io]) + (:import (java.io PushbackReader))) + +(def unsafe-keys [:plugins :hooks :middleware :certificates :mirrors :local-repo + :implicits :implicit-hooks :implicit-middleware]) + +(def profile-names [:base :system :provided :dev]) + +(defn- safely-read-project [{:keys [root]}] + (with-open [rdr (PushbackReader. (io/reader (io/file root "project.clj")))] + (let [items (repeatedly #(read {:eof ::eof} rdr)) + items (take-while #(not= ::eof %) items) + [_defproject project-name version & rest] (last items) + project (merge {:name (name project-name) + :group (or (namespace project-name) + (name project-name)) + :version version + :root root} + project/defaults + (apply hash-map rest) + {:repositories project/default-repositories + :plugin-repositories project/default-repositories}) + project (apply dissoc project unsafe-keys)] + (project/merge-profiles (project/init-project project profile-names) + profile-names)))) + +(defn ^:no-project-needed static-classpath + "Write the classpath of the current project to output-file or stdout. + +Does not load any plugins or other project code; should be safe to run on +untrusted projects; however, may be less accurate than `classpath`. +Suitable for use in static analysis." + ([project] + (classpath/classpath (safely-read-project project))) + ([project output-file] + (classpath/classpath (safely-read-project project) output-file))) diff --git a/src/leiningen/test.clj b/src/leiningen/test.clj index 085ede5b8..9d816ee54 100644 --- a/src/leiningen/test.clj +++ b/src/leiningen/test.clj @@ -250,6 +250,8 @@ This task uses the following exit codes: ;; never reload). :reloading-require (= :nrepl (:eval-in project))} (vec selectors))] - (try (eval/eval-in-project project form '(require 'clojure.test)) + (try (let [exit (eval/eval-in-project project form '(require 'clojure.test))] + (when (and (number? exit) (pos? exit)) + (throw (ex-info "Tests Failed" {:exit-code exit})))) (catch clojure.lang.ExceptionInfo e (main/abort (.getMessage e))))))) diff --git a/src/leiningen/uberjar.clj b/src/leiningen/uberjar.clj index f18500c4e..5bcb2fdeb 100644 --- a/src/leiningen/uberjar.clj +++ b/src/leiningen/uberjar.clj @@ -10,9 +10,11 @@ [leiningen.jar :as jar] [leiningen.pom :as pom] [clojure.set :as set]) - (:import (java.io File FileOutputStream PrintWriter) + (:import (java.io File FileOutputStream PrintWriter InputStream) (java.util.regex Pattern) (java.util.zip ZipFile ZipOutputStream ZipEntry) + (javax.xml.parsers SAXParser) + (org.xml.sax.helpers DefaultHandler) (org.apache.commons.io.output CloseShieldOutputStream) (org.apache.commons.lang StringEscapeUtils))) @@ -40,8 +42,13 @@ (assoc-in node [:content 0] (StringEscapeUtils/escapeXml content)) node))) +;; replace clojure.xml version with one that doesn't do illegal access +(defn- startparse [^InputStream ins ^DefaultHandler ch] + (let [^SAXParser p (xml/disable-external-entities (xml/sax-parser))] + (.parse p ins ch))) + (defn- components-read [ins] - (let [zipper (->> ins xml/parse zip/xml-zip)] + (let [zipper (-> ins (xml/parse startparse) zip/xml-zip)] (->> (tree-edit zipper html-escape-editor) zip/xml-zip zip/children (filter #(= (:tag %) :components)) first :content))) @@ -160,34 +167,34 @@ Note: The :uberjar profile is implicitly activated for this task, and cannot be deactivated." ([project main] - (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 (->> (into [:uberjar] provided-profiles) - (project/merge-profiles project)) - _ (check-for-snapshot-deps project) - project (update-in project [:jar-inclusions] - concat (:uberjar-inclusions project)) - [_ jar] (try (first (jar/jar project main)) - (catch Exception e - (when main/*debug* - (.printStackTrace e)) - (main/abort "Uberjar aborting because jar failed:" - (.getMessage e)))) - standalone-filename (jar/get-jar-filename project :standalone)] - (with-open [out (-> standalone-filename - (FileOutputStream.) - (ZipOutputStream.))] - (let [whitelisted (select-keys project project/whitelist-keys) - project (-> (project/unmerge-profiles project [:default]) - (merge whitelisted)) - deps (->> (classpath/resolve-managed-dependencies - :dependencies :managed-dependencies project) - (filter #(.endsWith (.getName %) ".jar"))) - jars (cons (io/file jar) deps)] - (write-components project jars out))) - (main/info "Created" standalone-filename) - standalone-filename)) + (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 (->> (into [:uberjar] provided-profiles) + (project/merge-profiles project)) + _ (check-for-snapshot-deps project) + project (update-in project [:jar-inclusions] + concat (:uberjar-inclusions project)) + [_ jar] (try (first (jar/jar project main)) + (catch Exception e + (when main/*debug* + (.printStackTrace e)) + (main/abort "Uberjar aborting because jar failed:" + (.getMessage e)))) + standalone-filename (jar/get-jar-filename project :standalone)] + (with-open [out (-> standalone-filename + (FileOutputStream.) + (ZipOutputStream.))] + (let [whitelisted (select-keys project project/whitelist-keys) + project (-> (project/unmerge-profiles project [:default]) + (merge whitelisted)) + deps (->> (classpath/resolve-managed-dependencies + :dependencies :managed-dependencies project) + (filter #(.endsWith (.getName %) ".jar"))) + jars (cons (io/file jar) deps)] + (write-components project jars out))) + (main/info "Created" standalone-filename) + standalone-filename)) ([project] (uberjar project nil))) diff --git a/test/leiningen/test/change.clj b/test/leiningen/test/change.clj index 364e95662..ae9424f3b 100644 --- a/test/leiningen/test/change.clj +++ b/test/leiningen/test/change.clj @@ -79,9 +79,9 @@ [:description] "set" "a dynamic description")))) (testing "can set a key with newlines and comments in place" - (is (= "(defproject leingingen.change \"0.0.1\"\n :description \"a static description\"\n ; whatever \n :url \"http://test.com\")" - (change-string "(defproject leingingen.change \"0.0.1\"\n :description \"a static description\"\n ; whatever \n :url \"http://old.com\")" - [:url] "set" "http://test.com")))) + (is (= "(defproject leingingen.change \"0.0.1\"\n :description \"a static description\"\n ; whatever \n :url \"https://test.com\")" + (change-string "(defproject leingingen.change \"0.0.1\"\n :description \"a static description\"\n ; whatever \n :url \"https://old.com\")" + [:url] "set" "https://test.com")))) (testing "can create a new key" (is (= "(defproject leingingen.change \"0.0.1\" :description \"a dynamic description\")" @@ -94,19 +94,19 @@ [:description] "set" "a dynamic description")))) (testing "can create a new key instead of replacing a nested one with the same name" - (is (= "(defproject leingingen.change \"0.0.1\"\n :description \"a dynamic description\"\n :license {:name \"Test\"\n :url \"http://test.com\"}\n :url \"http://new.com\")" - (change-string "(defproject leingingen.change \"0.0.1\"\n :description \"a dynamic description\"\n :license {:name \"Test\"\n :url \"http://test.com\"}\n)" - [:url] "set" "http://new.com")))) + (is (= "(defproject leingingen.change \"0.0.1\"\n :description \"a dynamic description\"\n :license {:name \"Test\"\n :url \"https://test.com\"}\n :url \"https://new.com\")" + (change-string "(defproject leingingen.change \"0.0.1\"\n :description \"a dynamic description\"\n :license {:name \"Test\"\n :url \"https://test.com\"}\n)" + [:url] "set" "https://new.com")))) (testing "can set a nested key" - (is (= "(defproject leingingen.change \"0.0.1\" :license {:url \"http://example.com\"})" - (change-string "(defproject leingingen.change \"0.0.1\" :license {:url \"http://old.com\"})" - [:license :url] "set" "http://example.com")))) + (is (= "(defproject leingingen.change \"0.0.1\" :license {:url \"https://example.com\"})" + (change-string "(defproject leingingen.change \"0.0.1\" :license {:url \"https://old.com\"})" + [:license :url] "set" "https://example.com")))) (testing "can set a nested key with newlines in place" - (is (= "(defproject leingingen.change \"0.0.1\"\n :license {:url \"http://example.com\"})" - (change-string "(defproject leingingen.change \"0.0.1\"\n :license {:url \"http://old.com\"})" - [:license :url] "set" "http://example.com")))) + (is (= "(defproject leingingen.change \"0.0.1\"\n :license {:url \"https://example.com\"})" + (change-string "(defproject leingingen.change \"0.0.1\"\n :license {:url \"https://old.com\"})" + [:license :url] "set" "https://example.com")))) (testing "can create a nested value" (is (= "(defproject leingingen.change \"0.0.1\" :a {:b {:c 1}})" @@ -114,9 +114,9 @@ [:a :b :c] "set" 1)))) (testing "can understand cli short form" - (is (= "(defproject leingingen.change \"0.0.1\" :license {:url \"http://example.com\"})" + (is (= "(defproject leingingen.change \"0.0.1\" :license {:url \"https://example.com\"})" (change-string "(defproject leingingen.change \"0.0.1\")" - ":license:url" "set" "http://example.com"))))) + ":license:url" "set" "https://example.com"))))) (deftest test-set-dependency-value (testing "can set dependency version" diff --git a/test/leiningen/test/check.clj b/test/leiningen/test/check.clj new file mode 100644 index 000000000..08e7a9153 --- /dev/null +++ b/test/leiningen/test/check.clj @@ -0,0 +1,24 @@ +(ns leiningen.test.check + (:require [clojure.test :refer :all] + [clojure.java.io :as io] + [leiningen.check :as check] + [leiningen.clean :as clean] + [leiningen.core.main :as main] + [leiningen.test.helper :as h]) + (:import (java.io ByteArrayOutputStream PrintStream))) + +(deftest works-with-aot + (binding [main/*exit-process?* false] + (let [project (doto (h/read-test-project "reflector") clean/clean) + old-err System/err + out (ByteArrayOutputStream.)] + (System/setErr (PrintStream. out)) + (try (binding [*err* (io/writer out)] + (check/check project)) + (catch clojure.lang.ExceptionInfo e + (when-not (is (= 1 (:exit-code (ex-data e)))) + (throw e))) + (finally (System/setErr old-err))) + (let [out-str (.toString out "UTF-8")] + (is (re-find #"field getBytes can't be resolved" out-str)) + (is (not (re-find #"ClassNotFoundException" out-str))))))) diff --git a/test/leiningen/test/deploy.clj b/test/leiningen/test/deploy.clj index 1d2159ca7..35474712e 100644 --- a/test/leiningen/test/deploy.clj +++ b/test/leiningen/test/deploy.clj @@ -3,19 +3,16 @@ [clojure.test :refer :all] [leiningen.deploy :refer :all] [leiningen.core.main :as main] - [leiningen.test.helper :refer [delete-file-recursively - tmp-dir - sample-project - sample-deploy-project - with-system-err-str - with-system-out-str]])) + [leiningen.core.eval :as eval] + [leiningen.core.utils :as utils] + [leiningen.test.helper :as help])) (use-fixtures :once (fn [f] (binding [main/*info* false] (f)))) (defn- repo-path [relative-repo-path] (clojure.string/replace - (format "%s/%s" tmp-dir relative-repo-path) + (format "%s/%s" help/tmp-dir relative-repo-path) "\\" "/")) ;make path delimiters look the same / even under Windows (defn- repo-url @@ -26,7 +23,7 @@ [project relative-repo-path & [explicit-deploy-repo?]] (let [repo-path (repo-path relative-repo-path) repo-url (repo-url repo-path)] - (delete-file-recursively repo-path :silently) + (help/delete-file-recursively repo-path :silently) (with-out-str (deploy project (if explicit-deploy-repo? repo-url @@ -39,15 +36,31 @@ (deftest ^:online test-deploy (testing "simple deployment to `snapshots` already defined in project.clj" - (deploy-snapshots sample-project "lein-repo"))) + (deploy-snapshots help/sample-project "lein-repo"))) + +(deftest ^:online test-deploy-password + (with-redefs [read-password-fn (constantly (constantly + (char-array "stupidhorse"))) + read-line (constantly "leiningen-test-fail-expected-sorry")] + (reset! utils/rebound-io? false) + (binding [main/*exit-process?* false + *err* (java.io.StringWriter.)] + (testing "provides password in a way pomegranate accepts" + (let [result (try + (with-out-str + (help/with-system-err-str + (deploy help/sample-project "clojars"))) + (catch Exception e + (.getMessage e)))] + (is (re-find #"401 Unauthorized" result))))))) (deftest ^:online test-deploy-custom-url (testing "deployment to a repo specified as a URL argument to `deploy`" - (deploy-snapshots sample-project "lein-custom-repo" true))) + (deploy-snapshots help/sample-project "lein-custom-repo" true))) (deftest ^:online test-deploy-repositories-key (testing "preferring repository in :deploy-repositories over :repositories" - (deploy-snapshots (assoc sample-project + (deploy-snapshots (assoc help/sample-project :deploy-repositories {"snapshots" {:url (-> "deploy-only-repo" repo-path repo-url)}}) @@ -56,10 +69,10 @@ (deftest ^:online test-deploy-classifier (testing "deployment with explicit file names uploads classifiers to repo" (let [deploy-dir (repo-path "deploy-classifier") - project (assoc sample-deploy-project + project (assoc help/sample-deploy-project :deploy-repositories {"snapshots" {:url (repo-url deploy-dir)}})] - (delete-file-recursively deploy-dir :silently) + (help/delete-file-recursively deploy-dir :silently) (with-out-str (deploy project "snapshots" "deploy-me/deploy-me" @@ -87,6 +100,23 @@ (is (= (sign-for-repo? ["foo" {:sign-releases false}]) false)) (is (= (sign-for-repo? ["foo" {}]) true)))) +(deftest ssh-signing + (let [file (str (:root help/sample-project) "/project.clj") + artifacts {[:extension "clj"] file}] + (io/delete-file (str file ".sig") :silently) + ;; git won't store file permissions so we need to set this manually + (binding [*out* (java.io.PrintWriter. (java.io.StringWriter.))] + (eval/sh "chmod" "600" "test_projects/.ssh/id_rsa")) + (binding [main/*exit-process?* false + eval/*sh-silent?* true] + (is (= [{[:extension "clj.sig"] (str file ".sig")}] + (binding [*out* (java.io.PrintWriter. (java.io.StringWriter.))] + (signatures-for-artifacts artifacts + {:ssh-key "test_projects/.ssh/id_rsa" + :gpg-key false})))) + (is (= 0 (binding [*out* (java.io.PrintWriter. (java.io.StringWriter.))] + (eval/sh "test_projects/.ssh/verify"))))))) + (deftest validate-input (testing "Fail if project data is missing" (is (thrown? clojure.lang.ExceptionInfo (binding [*err* (java.io.StringWriter.)] diff --git a/test/leiningen/test/deps.clj b/test/leiningen/test/deps.clj index 30ff5dc15..66de93b64 100644 --- a/test/leiningen/test/deps.clj +++ b/test/leiningen/test/deps.clj @@ -29,7 +29,7 @@ (doseq [[n v] sample-deps] (delete-file-recursively (m2-dir n v) :silently)) ;; For some reason running deps on a project that includes ring - ;; fails, but only when done right here. http://p.hagelb.org/mystery.gif + ;; fails, but only when done right here. https://p.hagelb.org/mystery.gif (deps (update-in sample-project [:dependencies] rest)) (doseq [[n v] sample-deps] (is (.exists (m2-dir n v)) (str n " was not downloaded."))))) @@ -74,6 +74,19 @@ [org.clojure/core.unify "0.5.3"]]] (is (.contains out (pr-str plugin-dep))))))) +(deftest ^:online test-plugin-dependency-hierarchy-as-edn + (let [sample-plugin-deps [["codox" "0.6.4"]]] + (doseq [[n v] sample-plugin-deps] + (delete-file-recursively (m2-dir n v) :silently)) + (let [out (with-out-str (deps sample-project ":plugin-tree-data"))] + (is (= '{[codox "0.6.4"] + {[codox/codox.leiningen "0.6.4"] + {[leinjacker "0.4.1"] + {[org.clojure/core.contracts "0.0.1"] + {[org.clojure/clojure "1.4.0"] nil + [org.clojure/core.unify "0.5.3"] nil}}}}} + (read-string out)))))) + (deftest ^:online test-snapshots-releases (let [pr (assoc sample-project :repositories ^:replace {"clojars" {:url "https://repo.clojars.org/" @@ -242,26 +255,3 @@ [jdom "1.0"] :unsigned}] (is (.contains out (pr-str signed dep)) (str "missing " dep))))) - -(deftest ^:online test-opengpg-org-server - ;; https://keys.openpgp.org/about/faq#older-gnupg - ;; https://dev.gnupg.org/T4393#133689 - (testing "Avoid infinite loop when `gpg --receive-keys` is run against openpgp.org keyservers" - (let [project (-> sample-project - (update :repositories (fn [repos] - (remove #(= "other" (first %)) repos))) - (update :dependencies #(conj (take 2 %) - '[commons-io "2.8.0"])) - (assoc :checksum :ignore)) - _ (with-system-out-str - (deps project)) - out (with-out-str - (with-system-out-str - (with-system-err-str - (deps project ":verify"))))] - (doseq [[dep signed] '{[org.clojure/clojure "1.3.0"] :signed - [commons-io "2.8.0"] :no-key - [rome "0.9"] :unsigned - [jdom "1.0"] :unsigned}] - (is (.contains out (pr-str signed dep)) - (str "missing " dep)))))) diff --git a/test/leiningen/test/helper.clj b/test/leiningen/test/helper.clj index dc6c347d4..a21b70b08 100644 --- a/test/leiningen/test/helper.clj +++ b/test/leiningen/test/helper.clj @@ -92,6 +92,8 @@ (def leaky-composite-project (read-test-project "leaky-composite")) +(def preserve-eval-meta-project (read-test-project "preserve-eval-meta")) + (defn abort-msg "Catches main/abort thrown by calling f on its args and returns its error message." diff --git a/test/leiningen/test/jar.clj b/test/leiningen/test/jar.clj index 904f4216c..87071a848 100644 --- a/test/leiningen/test/jar.clj +++ b/test/leiningen/test/jar.clj @@ -90,7 +90,10 @@ (deftest test-no-aot-jar-succeeds (with-out-str - (is (jar helper/sample-no-aot-project)))) + (let [project (helper/read-test-project "sample-no-aot") + jar (first (vals (jar project))) + entry-names (set (helper/walkzip jar #(.getName %)))] + (is (not (entry-names "dev.clj")))))) (deftest test-classifier-jar-succeeds (is (= 1 (count (:classifiers helper/with-classifiers-project))) @@ -108,9 +111,8 @@ (unmemoize #'leiningen.core.classpath/get-dependencies-memoized #'leiningen.core.classpath/get-dependencies*) (binding [main/*info* false] - (let [[coord jar-file] (first - (jar (dissoc helper/sample-project - :dependencies :main)))] + (let [project (helper/read-test-project "sample-bad-user") + [coord jar-file] (first (jar (dissoc project :dependencies :main)))] (is (.exists (io/file jar-file))) (is (= coord [:extension "jar"]))))) diff --git a/test/leiningen/test/new.clj b/test/leiningen/test/new.clj index 569c9dbdc..3112ae081 100644 --- a/test/leiningen/test/new.clj +++ b/test/leiningen/test/new.clj @@ -1,6 +1,6 @@ (ns leiningen.test.new - (:require [leiningen.new :as new]) - (:require [clojure.test :refer :all] + (:require [leiningen.new :as new] + [clojure.test :refer :all] [clojure.java.io :refer [file]] [leiningen.test.helper :refer [delete-file-recursively abort-msg]] [leiningen.new :as new] @@ -70,13 +70,14 @@ (constantly {:user {:mirrors {"clojars" "https://clojars.example.com" - "central" "http://central.exmaple.com"}}})] + "central" "https://central.exmaple.com"}}})] (let [name "luminus" sym (symbol (str "leiningen.new." name))] (leiningen.new/resolve-remote-template name sym)))))) (deftest ^:online test-group-id-template - (is (fn? @(new/resolve-template "us.technomancy/liquid-cool")))) + (is (fn? @(new/resolve-template "us.technomancy/liquid-cool"))) + (is (fn? @(new/resolve-template "net.ofnir/default")))) (deftest test-new-with-*-jure-project-name (is (re-find diff --git a/test/leiningen/test/pom.clj b/test/leiningen/test/pom.clj index c6688c74c..0bae05213 100644 --- a/test/leiningen/test/pom.clj +++ b/test/leiningen/test/pom.clj @@ -146,9 +146,9 @@ "version is correct") (is (nil? (first-in xml [::pom/project ::pom/parent])) "no parent") - (is (= "http://leiningen.org" (first-in xml [::pom/project ::pom/url])) + (is (= "https://leiningen.org" (first-in xml [::pom/project ::pom/url])) "url is correct") - (is (= ["Eclipse Public License" "http://www.eclipse.org/legal/epl-v10.html"] + (is (= ["Eclipse Public License" "https://www.eclipse.org/legal/epl-v10.html"] (->> (deep-content xml [::pom/project ::pom/licenses]) (map :content) first (map :content) (map first))) "no license") @@ -161,7 +161,7 @@ (deep-content xml [::pom/project ::pom/repositories]))) "repositories are named") (is (= ["https://repo1.maven.org/maven2/" "https://repo.clojars.org/" - "http://example.com/repo"] + "https://example.com/repo"] (map #(first-in % [::pom/repository ::pom/url]) (deep-content xml [::pom/project ::pom/repositories]))) "repositories have correct location") @@ -380,7 +380,7 @@ ((partial mapcat :content)))))) (deftest test-pom-handles-global-exclusions - (is (= [["clojure"] ["clojure"] ["clojure"]] + (is (= [["clojure"] ["clojure"]] (-> (make-pom (with-profile-merged sample-project ^:leaky {:exclusions '[org.clojure/clojure]})) parse-xml diff --git a/test/leiningen/test/repl.clj b/test/leiningen/test/repl.clj index 4924288e2..6b3a0d611 100644 --- a/test/leiningen/test/repl.clj +++ b/test/leiningen/test/repl.clj @@ -1,11 +1,18 @@ (ns leiningen.test.repl - (:require [clojure.test :refer :all] + (:require [clojure.java.io :as io] + [clojure.test :refer :all] [leiningen.repl :refer :all] [leiningen.test.helper :as helper] [leiningen.core.user :as user] [leiningen.core.project :as project] [leiningen.core.main :as main] - [nrepl.ack :as ack])) + [leiningen.core.utils :as utils] + [nrepl.ack :as ack] + [nrepl.core :as nrepl] + [nrepl.config]) + (:import + (java.io File) + (java.nio.file Files))) (deftest test-merge-repl-profile (is (= (-> {:repl-options {:ack-port 4}} @@ -48,25 +55,100 @@ nil prj 4 nil nil nil))) -(deftest test-repl-port - (let [env "3" - prj {:repl-options {:port 2}}] - (are [env proj exp] - (= exp (with-redefs [user/getenv {"LEIN_REPL_PORT" env}] - (repl-port proj))) - env prj 3 - nil prj 2 - nil nil 0))) - -(deftest test-repl-host - (let [env "env-host" - prj {:repl-options {:host "proj-host"}}] - (are [env proj exp] - (= exp (with-redefs [user/getenv {"LEIN_REPL_HOST" env}] - (repl-host proj))) - env prj "env-host" - nil prj "proj-host" - nil nil "127.0.0.1"))) +(deftest test-configured-repl-connection + (let [vhost "LEIN_REPL_HOST" + vport "LEIN_REPL_PORT" + vsock "LEIN_REPL_SOCKET"] + (are [context exp] + (= exp (let [[opts env proj nrepl] context] + (with-redefs [nrepl.config/config (or nrepl {}) + user/getenv (or env {})] + (configured-repl-connection proj opts)))) + + [nil nil nil nil] + {:host "127.0.0.1" :port 0} + + ;; port precedence + [[":port" "1"] {vport "2"} {:repl-options {:port 3}} {:port 4}] + {:host "127.0.0.1" :port 1} + [nil {vport "2"} {:repl-options {:port 3}} {:port 4}] + {:host "127.0.0.1" :port 2} + [nil nil {:repl-options {:port 3}} {:port 4}] + {:host "127.0.0.1" :port 3} + [nil nil nil {:port 4}] + {:host "127.0.0.1" :port 4} + + ;; host precedence + [[":host" "opt"] {vhost "env"} {:repl-options {:host "proj"}} {:host "nrepl"}] + {:host "opt" :port 0} + [nil {vhost "env"} {:repl-options {:host "proj"}} {:host "nrepl"}] + {:host "env" :port 0} + [nil nil {:repl-options {:host "proj"}} {:host "nrepl"}] + {:host "proj" :port 0} + [nil nil nil {:host "nrepl"}] + {:host "nrepl" :port 0} + [nil nil nil {:bind "nrepl"}] + {:host "nrepl" :port 0} + ;; REVIEW: appropriate to allow duplicates? + [nil nil nil {:host "host" :bind "bind"}] + {:host "host" :port 0} + + ;; socket precedence + [[":socket" "opt"] {vsock "env"} {:repl-options {:socket "proj"}} {:socket "nrepl"}] + {:socket "opt"} + [nil {vsock "env"} {:repl-options {:socket "proj"}} {:socket "nrepl"}] + {:socket "env"} + [nil nil {:repl-options {:socket "proj"}} {:socket "nrepl"}] + {:socket "proj"} + [nil nil nil {:socket "nrepl"}] + {:socket "nrepl"}))) + +(defmacro with-captured-abort [& body] + `(let [args# (atom nil)] + (with-redefs [main/abort #(reset! args# %&)] + (do ~@body) + (let [result# @args#] + (when-not (seq result#) + (throw (ex-info "Expected abort, none found" {}))) + @args#)))) + +(deftest test-configured-repl-connection-errors + (testing "conflicting arguments" + (is (= [":socket argument conflicts with :host and :port"] + (with-captured-abort + (configured-repl-connection nil [":socket" "foo" ":host" "bar"])))) + (is (= [":socket argument conflicts with :host and :port"] + (with-captured-abort + (configured-repl-connection nil [":socket" "foo" ":port" "bar"]))))) + (testing "conflicting environment vars" + (is (= ["LEIN_REPL_HOST conflicts with LEIN_REPL_HOST and LEIN_REPL_PORT"] + (with-captured-abort + (with-redefs [user/getenv {"LEIN_REPL_SOCKET" "foo" "LEIN_REPL_HOST" "bar"}] + (configured-repl-connection nil nil))))) + (is (= ["LEIN_REPL_HOST conflicts with LEIN_REPL_HOST and LEIN_REPL_PORT"] + (with-captured-abort + (with-redefs [user/getenv {"LEIN_REPL_SOCKET" "foo" "LEIN_REPL_PORT" "1"}] + (configured-repl-connection nil nil)))))) + (testing "conflicting project settings" + (is (= ["project :repl-options :socket conflicts with :host and :port"] + (with-captured-abort + (configured-repl-connection {:repl-options {:socket "foo" :host "bar"}} nil)))) + (is (= ["project :repl-options :socket conflicts with :host and :port"] + (with-captured-abort + (configured-repl-connection {:repl-options {:socket "foo" :port "bar"}} nil))))) + (testing "conflicticting nrepl settings" + (is (= ["nREPL config :socket conflicts with :bind, :host, and :port"] + (with-captured-abort + (with-redefs [nrepl.config/config {:socket "foo" :bind "bar"}] + (configured-repl-connection nil nil))))) + (is (= ["nREPL config :socket conflicts with :bind, :host, and :port"] + (with-captured-abort + (with-redefs [nrepl.config/config {:socket "foo" :host "bar"}] + (configured-repl-connection nil nil))))) + (is (= ["nREPL config :socket conflicts with :bind, :host, and :port"] + (with-captured-abort + (with-redefs [nrepl.config/config {:socket "foo" :port "bar"}] + (configured-repl-connection nil nil))))))) (deftest test-is-uri (is (= true (is-uri? "http://example.org"))) @@ -81,8 +163,8 @@ (deftest test-connect-string (are [in exp] - (= exp (with-redefs [repl-host (constantly "repl-host") - repl-port (constantly 5)] + (= exp (with-redefs [configured-repl-connection (constantly {:host "repl-host" + :port 5})] (connect-string {} [in]))) "" "repl-host:5" "7" "repl-host:7" @@ -95,8 +177,8 @@ "https://localhost/ham" "https://localhost/ham" "https://localhost:20" "https://localhost:20" "https://localhost:20/ham" "https://localhost:20/ham") - (with-redefs [repl-host (constantly "repl-host") - repl-port (constantly 0)] + (with-redefs [configured-repl-connection (constantly {:host "repl-host" + :port 0})] (is (= "repl-host:1" (connect-string {} ["1"]))) (is (= "repl-host:123" (connect-string {} ["123"]))) (are [in proj] @@ -173,3 +255,21 @@ (-> (mocked-repl project ":start" ":transport" 'nrepl.transport/edn) (select-keys [:attach :scheme])))))) + +(deftest ^:disabled test-headless-socket + (let [tmpdir (utils/create-tmpdir (-> "target" File. .getAbsoluteFile) + "socket-test-" "rwx------") + sock-path (str tmpdir "/socket") + sock-file (io/as-file sock-path)] + (try + (let [server (future (repl helper/sample-ordered-aot-project + ":headless" ":socket" sock-path))] + (while (not (.exists sock-file)) + (Thread/sleep 100)) + (is (= [42] (with-open [conn (nrepl/connect :socket sock-path)] + (-> (nrepl/client conn 3000) + (nrepl/message {:op "eval" :code "(+ 21 21)"}) + nrepl/response-values))))) + (finally + (.delete sock-file) + (Files/delete tmpdir))))) diff --git a/test/leiningen/test/run.clj b/test/leiningen/test/run.clj index 984fa31f7..4a6af9674 100644 --- a/test/leiningen/test/run.clj +++ b/test/leiningen/test/run.clj @@ -5,7 +5,8 @@ [leiningen.test.helper :as helper :refer [bad-require-project tmp-dir tricky-name-project java-main-project file-not-found-thrower-project - with-system-out-str with-system-err-str]] + with-system-out-str with-system-err-str + preserve-eval-meta-project]] [clojure.test :refer :all] [leiningen.run :refer :all])) @@ -83,3 +84,21 @@ ;; 'file-not-found-thrower.core' as .class or .clj for lein run: ;; please check the spelling." is not (is (.contains s "Exception in thread \"main\" java.io.FileNotFoundException")))) + +(deftest test-preserve-eval-meta + ;; By default, metadata (including type hints) is not preserved when dumping the code + ;; to be evaluated in the project. That's the case because some plugins include objects + ;; with metadata that can't be read (i.e. #object tags, referring to functions or vars). + ;; See https://github.com/technomancy/leiningen/issues/2814 + (let [err (with-system-err-str (run tricky-name-project "/unreadable"))] + (is (re-find #"Reflection warning.*call to.*can't be resolved" err))) + + ;; One consequence of not including type hints in the code to be evaluated is that + ;; `lein run` will print a reflection warning in projects with + ;; `:global-vars {*warn-on-reflection* true}`, because the code injected to run the + ;; main function needs type hints to avoid reflection. Including metadata is available + ;; as opt-in, using the :preserve-eval-meta project key. When that is set to true, no + ;; reflection warning should happen, but some plugins can't be loaded. + ;; See https://github.com/technomancy/leiningen/issues/2695 + (let [err (with-system-err-str (run preserve-eval-meta-project))] + (is (not (re-find #"Reflection warning.*call to.*can't be resolved" err))))) diff --git a/test/leiningen/test/search.clj b/test/leiningen/test/search.clj new file mode 100644 index 000000000..f779b931f --- /dev/null +++ b/test/leiningen/test/search.clj @@ -0,0 +1,48 @@ +(ns leiningen.test.search + (:import (com.sun.net.httpserver HttpExchange HttpHandler HttpServer) + (java.net InetSocketAddress)) + (:require [clojure.data.xml :as xml] + [clojure.string :as str] + [clojure.test :refer :all] + [leiningen.search :as search])) + +;;; Setting up a mock server for querying + +(def server (atom nil)) + +(defn start-server! [^InetSocketAddress sock] + (let [mock-element (xml/element "error" + {:message "Invalid search syntax query" + :id "24c1c717-98dd-4312-9fa8-8d63dab5ce74"}) + mock-error (xml/emit-str mock-element) + handle-search (reify HttpHandler + (^void handle [this ^HttpExchange exchange] + (with-open [response (.getResponseBody exchange)] + (.sendResponseHeaders exchange 400 (count mock-error)) + (.write response (.getBytes ^String mock-error)))))] + (reset! server (doto (HttpServer/create sock 0) + (.createContext "/search" handle-search) + (.start))))) + +(defn stop-server! [] + (.stop ^HttpServer @server 0) + (reset! server nil)) + +;;; Actual testing code + +(use-fixtures :once + (fn [f] + (let [sock (InetSocketAddress. 50000)] + (start-server! sock) + (f) + (stop-server!)))) + +(deftest parse-error-handling + (testing "parse reports helpful errors" + (let [url "http://localhost:50000/search?q=foobar" + result (with-out-str + ;; direct stderr to stdout so we can get a string and + ;; inspect it + (binding [*err* *out*] + (search/parse url)))] + (is (str/includes? result "syntax unsupported"))))) diff --git a/test/leiningen/test/static_classpath.clj b/test/leiningen/test/static_classpath.clj new file mode 100644 index 000000000..2171189a9 --- /dev/null +++ b/test/leiningen/test/static_classpath.clj @@ -0,0 +1,61 @@ +(ns leiningen.test.static-classpath + (:require [clojure.test :refer :all] + [clojure.string :as str] + [leiningen.core.main :as main] + [leiningen.test.helper :as helper]) + (:import (java.io File))) + +(defn- relativize [paths-str root] + (for [path (str/split paths-str #":")] + (-> path + (str/replace root "") + (str/replace (System/getenv "HOME") "~") + (str/replace "~/.m2/repository/" "$REPO/")))) + +(deftest test-static-classpath + (let [tmp (File/createTempFile "lein" "static-cp") + {:keys [root]} helper/leaky-composite-project] + (try + ;; static protections will wipe out these things; with-redefs can restore + ;; them back to their root values for us + (with-redefs [*read-eval* false + eval eval + load-file load-file] + (try (binding [main/*cwd* root] + (main/-main "static-classpath" (str tmp))) + (catch Exception e + ;; suppressed exit + (is (zero? (:exit-code (ex-data e))))))) + (is (= #{"$REPO/clj-stacktrace/clj-stacktrace/0.2.8/clj-stacktrace-0.2.8.jar" + "$REPO/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" + "$REPO/commons-fileupload/commons-fileupload/1.4/commons-fileupload-1.4.jar" + "$REPO/commons-io/commons-io/2.6/commons-io-2.6.jar" + "$REPO/crypto-equality/crypto-equality/1.0.0/crypto-equality-1.0.0.jar" + "$REPO/crypto-random/crypto-random/1.2.0/crypto-random-1.2.0.jar" + "$REPO/hiccup/hiccup/1.0.5/hiccup-1.0.5.jar" + "$REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar" + "$REPO/nrepl/nrepl/1.0.0/nrepl-1.0.0.jar" + "$REPO/ns-tracker/ns-tracker/0.4.0/ns-tracker-0.4.0.jar" + "$REPO/org/clojure/clojure/1.10.1/clojure-1.10.1.jar" + "$REPO/org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.jar" + "$REPO/org/clojure/java.classpath/0.3.0/java.classpath-0.3.0.jar" + "$REPO/org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.jar" + "$REPO/org/clojure/tools.namespace/0.2.11/tools.namespace-0.2.11.jar" + "$REPO/org/eclipse/jetty/jetty-http/9.4.31.v20200723/jetty-http-9.4.31.v20200723.jar" + "$REPO/org/eclipse/jetty/jetty-io/9.4.31.v20200723/jetty-io-9.4.31.v20200723.jar" + "$REPO/org/eclipse/jetty/jetty-server/9.4.31.v20200723/jetty-server-9.4.31.v20200723.jar" + "$REPO/org/eclipse/jetty/jetty-util/9.4.31.v20200723/jetty-util-9.4.31.v20200723.jar" + "$REPO/org/nrepl/incomplete/0.1.0/incomplete-0.1.0.jar" + "$REPO/ring/ring-codec/1.1.2/ring-codec-1.1.2.jar" + "$REPO/ring/ring-core/1.8.2/ring-core-1.8.2.jar" + "$REPO/ring/ring-devel/1.8.2/ring-devel-1.8.2.jar" + "$REPO/ring/ring-jetty-adapter/1.8.2/ring-jetty-adapter-1.8.2.jar" + "$REPO/ring/ring-servlet/1.8.2/ring-servlet-1.8.2.jar" + "$REPO/ring/ring/1.8.2/ring-1.8.2.jar" + "/dev-resources" + "/src" + "/target/classes" + "/test"} + (set (relativize (slurp tmp) root)))) + (finally + (.delete tmp))))) diff --git a/test/leiningen/test/test.clj b/test/leiningen/test/test.clj index 03a30d8df..948515105 100644 --- a/test/leiningen/test/test.clj +++ b/test/leiningen/test/test.clj @@ -82,12 +82,12 @@ (test lein-test-reload-bug-project)) (deftest test-failure-exit-code - (let [exit (promise)] - ;; suppress output; there's a lot of bad-looking stuff here - (with-out-str - ;; but get the exit code - (deliver exit (test lein-test-exit-code-project))) - (is (= 1 @exit)))) + (is (= 1 (try + ;; suppress output; there's a lot of bad-looking stuff here + (with-out-str + (test lein-test-exit-code-project)) + (catch clojure.lang.ExceptionInfo e + (:exit-code (ex-data e))))))) (deftest test-invalid-namespace-argument (is (.contains diff --git a/test/leiningen/test/uberjar.clj b/test/leiningen/test/uberjar.clj index 7f4875c99..d8f8916e4 100644 --- a/test/leiningen/test/uberjar.clj +++ b/test/leiningen/test/uberjar.clj @@ -1,7 +1,7 @@ (ns leiningen.test.uberjar (:require [leiningen.uberjar :refer :all] [clojure.test :refer :all] - [clojure.java.io :refer [delete-file]] + [clojure.java.io :as io] [clojure.java.shell :refer [sh]] [clojure.xml :as xml] [leiningen.test.helper :refer [unmemoize @@ -10,14 +10,15 @@ data-readers-backwards-compatibility-project provided-project managed-deps-project - managed-deps-snapshot-project]]) + managed-deps-snapshot-project] :as h]) (:import (java.io File FileOutputStream) (java.util.zip ZipFile))) (deftest test-uberjar - (with-out-str - (uberjar sample-no-aot-project)) - (let [filename (str "test_projects/sample-no-aot/target/" + (let [project (h/read-test-project "sample-no-aot") + _ (with-out-str + (uberjar sample-no-aot-project)) + filename (str "test_projects/sample-no-aot/target/" "nomnomnom-0.5.0-SNAPSHOT-standalone.jar") uberjar-file (File. filename)] (is (= true (.exists uberjar-file))) @@ -30,7 +31,7 @@ (.deleteOnExit uberjar-file) (is (entries "nom/nom/nom.clj")) (is (entries "org/codehaus/janino/Compiler$1.class")) - (is (not (some #(re-find #"dummy" %) entries))) + (is (not (entries "dev.clj"))) (is (not (entries "module-info.class"))))))) (deftest test-uberjar-merge-with @@ -71,18 +72,19 @@ (read-string contents)))))))) (deftest test-components-merger - (let [file1 (str "test_projects/uberjar-components-merging/components1.xml") - file2 (str "test_projects/uberjar-components-merging/components2.xml") - readxml (components-merger 0) - combine (components-merger 1) - writexml (components-merger 2) - combined-xml (combine (readxml file1) (readxml file2)) - expected-xml (xml/parse "test_projects/uberjar-components-merging/expected-components.xml") + (let [file1 (io/input-stream "test_projects/uberjar-components-merging/components1.xml") + file2 (io/input-stream "test_projects/uberjar-components-merging/components2.xml") + [read-xml combine write-xml] components-merger + combined-xml (combine (read-xml file1) (read-xml file2)) + expected-xml (xml/parse (io/input-stream + "test_projects/uberjar-components-merging/expected-components.xml") + #'leiningen.uberjar/startparse) result-file "test_projects/uberjar-components-merging/result-components.xml" out-file (FileOutputStream. (File. result-file))] - (writexml out-file combined-xml) - (is (= expected-xml (xml/parse result-file))) - (delete-file result-file true))) + (write-xml out-file combined-xml) + (is (= expected-xml (xml/parse (io/input-stream result-file) + #'leiningen.uberjar/startparse))) + (io/delete-file result-file true))) ;; TODO: this breaks on Java 6 (deftest ^:disabled test-uberjar-provided diff --git a/test_projects/.ssh/allowed_signers b/test_projects/.ssh/allowed_signers new file mode 100644 index 000000000..6827e865e --- /dev/null +++ b/test_projects/.ssh/allowed_signers @@ -0,0 +1 @@ +phil@hagelb.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCl/xWvwO2cw7yuHnv1spMGIBBFB5pFXduh3P8RD2dOqAv4CM9mrQ2BjSMbz0WePHvKYDNecrpG/vGHZHs5Anflj8nLRKjeihpQ5NpkQd51ICrR8u6dtjqIvXFMJZc3mW8IycUOb63+FNRxnNychc/RBPTJ8Gm1f0FBNpiSBZ8GpW1SjDuTM6bBPSmpQ6cLkrwCPMVPgKkUeXou7at13lKN7BZbW4KNhJVpHXpcxUTYVyvrZIochEVKlub+o0TWyzASQQFzNXU89nUjto51qAG4deYWKPOQYETpqgK7H4j8YqO6FUXwiHmnUPdRo22tuMlm9vDQubAXQ8of9ZOQQdiIsTRAemqgbU+e8cegxNqGtlabVNV9P36ATm2XAL8ovgrRAN0Q2Ict2MPKxG0ZH/9ct5GH/PWrSnWaYEcdjfQkJiJdSPL9omwzLWUnMAtTkGtxGkT81SPwbuOPzjQ4xMIK05sayWJtWx9kSPuX912798UjAk5kuHSR2olA9MPmtN0= phil@whirlwind diff --git a/test_projects/.ssh/id_rsa b/test_projects/.ssh/id_rsa new file mode 100644 index 000000000..0f6c7c873 --- /dev/null +++ b/test_projects/.ssh/id_rsa @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn +NhAAAAAwEAAQAAAYEApf8Vr8DtnMO8rh579bKTBiAQRQeaRV3bodz/EQ9nTqgL+AjPZq0N +gY0jG89Fnjx7ymAzXnK6Rv7xh2R7OQJ35Y/Jy0So3ooaUOTaZEHedSAq0fLunbY6iL1xTC +WXN5lvCMnFDm+t/hTUcZzcnIXP0QT0yfBptX9BQTaYkgWfBqVtUow7kzOmwT0pqUOnC5K8 +AjzFT4CpFHl6Lu2rdd5SjewWW1uCjYSVaR16XMVE2Fcr62SKHIRFSpbm/qNE1sswEkEBcz +V1PPZ1I7aOdagBuHXmFijzkGBE6aoCux+I/GKjuhVF8Ih5p1D3UaNtrbjJZvbw0LmwF0PK +H/WTkEHYiLE0QHpqoG1PnvHHoMTahrZWm1TVfT9+gE5tlwC/KL4K0QDdENiHLdjDysRtGR +//XLeRh/z1q0p1mmBHHY30JCYiXUjy/aJsMy1lJzALU5BrcRpE/NUj8G7jj840OMTCCtOb +GslibVsfZEj7l/ddu/fFIwJOZLh0kdqJQPTD5rTdAAAFiODHXAPgx1wDAAAAB3NzaC1yc2 +EAAAGBAKX/Fa/A7ZzDvK4ee/WykwYgEEUHmkVd26Hc/xEPZ06oC/gIz2atDYGNIxvPRZ48 +e8pgM15yukb+8YdkezkCd+WPyctEqN6KGlDk2mRB3nUgKtHy7p22Ooi9cUwllzeZbwjJxQ +5vrf4U1HGc3JyFz9EE9MnwabV/QUE2mJIFnwalbVKMO5MzpsE9KalDpwuSvAI8xU+AqRR5 +ei7tq3XeUo3sFltbgo2ElWkdelzFRNhXK+tkihyERUqW5v6jRNbLMBJBAXM1dTz2dSO2jn +WoAbh15hYo85BgROmqArsfiPxio7oVRfCIeadQ91Gjba24yWb28NC5sBdDyh/1k5BB2Iix +NEB6aqBtT57xx6DE2oa2VptU1X0/foBObZcAvyi+CtEA3RDYhy3Yw8rEbRkf/1y3kYf89a +tKdZpgRx2N9CQmIl1I8v2ibDMtZScwC1OQa3EaRPzVI/Bu44/ONDjEwgrTmxrJYm1bH2RI ++5f3Xbv3xSMCTmS4dJHaiUD0w+a03QAAAAMBAAEAAAGAHpeKOZ/GqrNwHG7FzZwheGmEVh +R2m/4WMhh2cYBzO43A1u9YucV+zbdjFwb1/5mJ/twH24otRlRJ0vfztaf8zLPZLrrynEC7 +ZNkoXn29L7zD53lr/GjPFNBFBxGOctK2Idp9lJGEcWUJWf7csYP/rrfJHUZPVQGk1w3mxF +KA4kqugR4TBKfqPYa2HNm4+WsLdyYX/vTpNDrHB8sJZGmasUknPaL5xnb+yiaCnIJGk9BM +6c7XnTXLR1nULG2OjD9ZyqU+M/D2vOaP0FFUyeLD16RIxZWdxDVmR9oPK6X54m9m9TgVG7 +QQaPZwAfP4bZHuq+CYhgUPq3YKYgrc9vNhKBobtwUarDjkquKUI8yArhwVXuopW9/pRbky +Xf+D98YSoexrnpSFmJeH3Z8r5Gdd8SQgoeP4NBhVwJT1soU1hvszTzWkQCfbfi3BmFBZxt +Wp8eJK5DH6edBkpwnIUmH26CuNkREfb/PE/jy6Tlg9WP2ST45NRg85EZ4HYbyPwbPBAAAA +wH5ogY8+kkbhqpHn2qmfTjdLkaUJuIHLEAlAy3CKGp1jZ8sJNjl0ZIzn5GV5aRbhmVTGoE +hw+ta0x6b10KF49i8/eHE0bpgtNOkX1ufTDw6IHY50vePGkyCi4TMwMUGLW+9bCz3CyIgP +eiQJ+fLb3oDSqiqsq2ZAFRRlabN/KcVuzft5MsgZbdIu/VKgCm6i2k2QYSf7+zGvKr6ceK +HgQ3autVKYW47/pqPxyqGrQ9a+1FG9O9VEVRYjjSZ0u3ZCfgAAAMEA0Y4/mmFKWAaEskUq +APJPeem0qB/z/PT4BGM7/VMONl7rH/ayJv6evtYBw1fSZ3VNt45HHzZPktR6aLjp7KZmR6 +Zyorze+Van2vAfAs0/GolZOCPp83lsXSKmgTq62a4aZ17F4rKKO+H/x20oi0I33PByaOiY +eap5c+5JpO1nx/8p2bHCCMNmlNB3xPhGYVZobe6Fuwj9yfPL1X1JB+1uuTw+fABLIMqaMD +1zPtTSRpgNDXN0hsIQ4Erkxap+f7GpAAAAwQDKyWBHqCazT+XIyWpSjU2kPcK/13/QDl5g +alz7U4wwAelA/cJ25LJnIISzz9vYjDigYCI9n+mvFh+vU2fEaSAyIsvEISD38ASmOLP4Sg +FcOHJH8YofYzDAY8ZBGYcvcAf7b7J66my/1W/B6M6L2OWg4kG2UX1zvmH0SA8zozfJH9fH +hf3sAldZEcXJ8ziQZlYby4uSaC0xD2jKq3rO9DV49n45KMyq/INLqa6wfdHCYQxKnmQYyn +LEXAgFW/V9UhUAAAAOcGhpbEB3aGlybHdpbmQBAgMEBQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/test_projects/.ssh/id_rsa.pub b/test_projects/.ssh/id_rsa.pub new file mode 100644 index 000000000..4bf99f381 --- /dev/null +++ b/test_projects/.ssh/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCl/xWvwO2cw7yuHnv1spMGIBBFB5pFXduh3P8RD2dOqAv4CM9mrQ2BjSMbz0WePHvKYDNecrpG/vGHZHs5Anflj8nLRKjeihpQ5NpkQd51ICrR8u6dtjqIvXFMJZc3mW8IycUOb63+FNRxnNychc/RBPTJ8Gm1f0FBNpiSBZ8GpW1SjDuTM6bBPSmpQ6cLkrwCPMVPgKkUeXou7at13lKN7BZbW4KNhJVpHXpcxUTYVyvrZIochEVKlub+o0TWyzASQQFzNXU89nUjto51qAG4deYWKPOQYETpqgK7H4j8YqO6FUXwiHmnUPdRo22tuMlm9vDQubAXQ8of9ZOQQdiIsTRAemqgbU+e8cegxNqGtlabVNV9P36ATm2XAL8ovgrRAN0Q2Ict2MPKxG0ZH/9ct5GH/PWrSnWaYEcdjfQkJiJdSPL9omwzLWUnMAtTkGtxGkT81SPwbuOPzjQ4xMIK05sayWJtWx9kSPuX912798UjAk5kuHSR2olA9MPmtN0= phil@whirlwind diff --git a/test_projects/.ssh/verify b/test_projects/.ssh/verify new file mode 100755 index 000000000..590f20680 --- /dev/null +++ b/test_projects/.ssh/verify @@ -0,0 +1,3 @@ +#!/bin/bash + +ssh-keygen -Y verify -f test_projects/.ssh/allowed_signers -I phil@hagelb.org -n file -s test_projects/sample/project.clj.sig < test_projects/sample/project.clj > /dev/null diff --git a/test_projects/bad-require/project.clj b/test_projects/bad-require/project.clj index cedc634f2..4206f06fa 100644 --- a/test_projects/bad-require/project.clj +++ b/test_projects/bad-require/project.clj @@ -1,7 +1,7 @@ (defproject bad-require "0.1.0-SNAPSHOT" :description "FIXME: write description" - :url "http://example.com/FIXME" + :url "https://example.com/FIXME" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]] :main bad-require.core) diff --git a/test_projects/file-not-found-thrower/project.clj b/test_projects/file-not-found-thrower/project.clj index f432c6274..4d264111c 100644 --- a/test_projects/file-not-found-thrower/project.clj +++ b/test_projects/file-not-found-thrower/project.clj @@ -1,6 +1,6 @@ (defproject file-not-found-thrower "0.1.0-SNAPSHOT" :description "FIXME: write description" - :url "http://example.com/FIXME" + :url "https://example.com/FIXME" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]]) diff --git a/test_projects/more-gen-classes/doc/intro.md b/test_projects/more-gen-classes/doc/intro.md index 53e64ff4d..e5669da0a 100644 --- a/test_projects/more-gen-classes/doc/intro.md +++ b/test_projects/more-gen-classes/doc/intro.md @@ -1,3 +1,3 @@ # Introduction to more-gen-classes -TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) +TODO: write [great documentation](https://jacobian.org/writing/what-to-write/) diff --git a/test_projects/more-gen-classes/project.clj b/test_projects/more-gen-classes/project.clj index ab0560b35..340816cfa 100644 --- a/test_projects/more-gen-classes/project.clj +++ b/test_projects/more-gen-classes/project.clj @@ -1,6 +1,6 @@ (defproject more-gen-classes "0.1.0-SNAPSHOT" :description "FIXME: write description" - :url "http://example.com/FIXME" + :url "https://example.com/FIXME" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]]) diff --git a/test_projects/preserve-eval-meta/.gitignore b/test_projects/preserve-eval-meta/.gitignore new file mode 100644 index 000000000..6eae6a532 --- /dev/null +++ b/test_projects/preserve-eval-meta/.gitignore @@ -0,0 +1,4 @@ +pom.xml +*jar +lib +classes diff --git a/test_projects/preserve-eval-meta/project.clj b/test_projects/preserve-eval-meta/project.clj new file mode 100644 index 000000000..a6cd8d516 --- /dev/null +++ b/test_projects/preserve-eval-meta/project.clj @@ -0,0 +1,6 @@ +(defproject preserve-eval-meta "1.0" + :description "Basic project with main invoked via lein run without reflection warnings" + :dependencies [[org.clojure/clojure "1.11.1"]] + :global-vars {*warn-on-reflection* true} + :preserve-eval-meta true + :main ^{:skip-aot true} preserve-eval-meta.core) diff --git a/test_projects/preserve-eval-meta/src/preserve_eval_meta/core.clj b/test_projects/preserve-eval-meta/src/preserve_eval_meta/core.clj new file mode 100644 index 000000000..53effb23a --- /dev/null +++ b/test_projects/preserve-eval-meta/src/preserve_eval_meta/core.clj @@ -0,0 +1,4 @@ +(ns preserve-eval-meta.core) + +(defn -main [& args] + (System/exit 0)) diff --git a/test_projects/provided/project.clj b/test_projects/provided/project.clj index 811757e90..8dfe09f02 100644 --- a/test_projects/provided/project.clj +++ b/test_projects/provided/project.clj @@ -1,6 +1,6 @@ (defproject provided "0" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [] :java-source-paths ["src"] :main provided.core.Example diff --git a/test_projects/reflector/.gitignore b/test_projects/reflector/.gitignore new file mode 100644 index 000000000..d956ab0a1 --- /dev/null +++ b/test_projects/reflector/.gitignore @@ -0,0 +1,13 @@ +/target +/classes +/checkouts +profiles.clj +pom.xml +pom.xml.asc +*.jar +*.class +/.lein-* +/.nrepl-port +/.prepl-port +.hgignore +.hg/ diff --git a/test_projects/reflector/project.clj b/test_projects/reflector/project.clj new file mode 100644 index 000000000..af9f9a5f2 --- /dev/null +++ b/test_projects/reflector/project.clj @@ -0,0 +1,7 @@ +(defproject reflector "0.1.0-SNAPSHOT" + :description "a sample project involving AOT" + :url "https://leiningen.org" + :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.11.1"]] + :aot [reflector.classy]) diff --git a/test_projects/reflector/src/reflector/classy.clj b/test_projects/reflector/src/reflector/classy.clj new file mode 100644 index 000000000..74a587cd3 --- /dev/null +++ b/test_projects/reflector/src/reflector/classy.clj @@ -0,0 +1,5 @@ +(ns reflector.classy + (:gen-class :extends java.lang.RuntimeException)) + +(defn init [xyz] (.getBytes xyz)) + diff --git a/test_projects/reflector/src/reflector/main.clj b/test_projects/reflector/src/reflector/main.clj new file mode 100644 index 000000000..df4275ee8 --- /dev/null +++ b/test_projects/reflector/src/reflector/main.clj @@ -0,0 +1,6 @@ +(ns reflector.main + (:require [reflector.classy]) + (:import reflector.classy)) + +(defn -main [& args] + (prn (classy.))) diff --git a/test_projects/sample-bad-user/project.clj b/test_projects/sample-bad-user/project.clj new file mode 100644 index 000000000..be2f31efc --- /dev/null +++ b/test_projects/sample-bad-user/project.clj @@ -0,0 +1,25 @@ +(def clj-version "1.3.0") + +(defproject nomnomnom "0.5.0-SNAPSHOT" + :description "A test project" + :url "https://leiningen.org" + :license {:name "Eclipse Public License" + :url "https://www.eclipse.org/legal/epl-v10.html"} + :dependencies [[~(symbol "org.clojure" "clojure") ~clj-version] + [rome ~(str "0." "9")] + [ring "1.0.0"]] + :plugins [[codox "0.6.4"]] + :main nom.nom.nom + :global-vars {*warn-on-reflection* true} + :jar-exclusions [#"^META-INF"] + :filespecs [{:type :fn :fn (fn [p] {:type :bytes :path "bytes.clj" + :bytes (str "[:bytes \"are\" " + (:name p) "]")})}] + :test-selectors {:integration :integration + :default (complement :integration) + :random (fn [_] (> (rand) ~(float 1/2)))} + :repositories [["other" {:url "https://example.com/repo" + :update :always + :releases {:checksum :warn}}]] + :deploy-repositories {"snapshots" ~(format "file://%s/lein-repo" + (System/getProperty "java.io.tmpdir"))}) diff --git a/test_projects/sample-bad-user/src/nom/nom/check.clj b/test_projects/sample-bad-user/src/nom/nom/check.clj new file mode 100644 index 000000000..be6d1df24 --- /dev/null +++ b/test_projects/sample-bad-user/src/nom/nom/check.clj @@ -0,0 +1,5 @@ +(ns nom.nom.check + (:require [sample2.core]) + (:gen-class)) + +(defn -main []) diff --git a/test_projects/sample-bad-user/src/nom/nom/nom.clj b/test_projects/sample-bad-user/src/nom/nom/nom.clj new file mode 100644 index 000000000..b87e26bcc --- /dev/null +++ b/test_projects/sample-bad-user/src/nom/nom/nom.clj @@ -0,0 +1,14 @@ +(ns nom.nom.nom + (:import [org.jdom.adapters CrimsonDOMAdapter]) + (:gen-class)) + +(when-not (= "1.3.0" (clojure-version)) + (throw (Exception. (str "Not running Clojure 1.3.0: " + (clojure-version))))) + +(def unused-proxy (proxy [Object] [] (toString [] "unused"))) + +(defn -main [& args] + (when-not (empty? args) + (println "NOM! Munched" (first args)) + (recur (rest args)))) diff --git a/test_projects/sample-bad-user/test/user.clj b/test_projects/sample-bad-user/test/user.clj new file mode 100644 index 000000000..0baac3664 --- /dev/null +++ b/test_projects/sample-bad-user/test/user.clj @@ -0,0 +1,3 @@ +(ns user) + +(throw (Exception. "loaded user!")) diff --git a/test_projects/sample-deploy/project.clj b/test_projects/sample-deploy/project.clj index c174326e9..7caa8eb05 100644 --- a/test_projects/sample-deploy/project.clj +++ b/test_projects/sample-deploy/project.clj @@ -1,6 +1,6 @@ (defproject deploy-me "0.1.0-SNAPSHOT" :description "FIXME: write description" - :url "http://example.com/FIXME" + :url "https://example.com/FIXME" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]]) diff --git a/test_projects/sample-no-aot/dev-resources/dev.clj b/test_projects/sample-no-aot/dev-resources/dev.clj new file mode 100644 index 000000000..908225b56 --- /dev/null +++ b/test_projects/sample-no-aot/dev-resources/dev.clj @@ -0,0 +1 @@ +"don't include me in the uberjar!" diff --git a/test_projects/sample-ordered-aot/project.clj b/test_projects/sample-ordered-aot/project.clj index 2e36ccf01..6dbae02fd 100644 --- a/test_projects/sample-ordered-aot/project.clj +++ b/test_projects/sample-ordered-aot/project.clj @@ -1,7 +1,7 @@ (defproject sample-ordered-aot "0.1.0-SNAPSHOT" :description "This project is to drive testing of ordered aot compilation." - :url "http://example.com/FIXME" + :url "https://example.com/FIXME" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]] :aot :all) diff --git a/test_projects/sample/project.clj b/test_projects/sample/project.clj index 35af4f15e..be2f31efc 100644 --- a/test_projects/sample/project.clj +++ b/test_projects/sample/project.clj @@ -2,9 +2,9 @@ (defproject nomnomnom "0.5.0-SNAPSHOT" :description "A test project" - :url "http://leiningen.org" + :url "https://leiningen.org" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} + :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies [[~(symbol "org.clojure" "clojure") ~clj-version] [rome ~(str "0." "9")] [ring "1.0.0"]] @@ -18,7 +18,7 @@ :test-selectors {:integration :integration :default (complement :integration) :random (fn [_] (> (rand) ~(float 1/2)))} - :repositories [["other" {:url "http://example.com/repo" + :repositories [["other" {:url "https://example.com/repo" :update :always :releases {:checksum :warn}}]] :deploy-repositories {"snapshots" ~(format "file://%s/lein-repo" diff --git a/test_projects/tricky-name/project.clj b/test_projects/tricky-name/project.clj index df95e09e4..8f39610f1 100644 --- a/test_projects/tricky-name/project.clj +++ b/test_projects/tricky-name/project.clj @@ -1,4 +1,5 @@ (defproject org.domain/tricky-name "1.0" :description "One with a tricky group and project name" :dependencies [[org.clojure/clojure "1.3.0"]] + :global-vars {*warn-on-reflection* true} :main ^{:skip-aot true} org.domain.tricky-name.core) diff --git a/test_projects/uberjar-components-merging/components2.xml b/test_projects/uberjar-components-merging/components2.xml index 914663bc3..f31b7ab3b 100644 --- a/test_projects/uberjar-components-merging/components2.xml +++ b/test_projects/uberjar-components-merging/components2.xml @@ -9,7 +9,7 @@ "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an diff --git a/web/.htaccess b/web/.htaccess index 98ad541dc..cc4579d2f 100644 --- a/web/.htaccess +++ b/web/.htaccess @@ -7,3 +7,7 @@ RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L] Header set Strict-Transport-Security "max-age=31536000" env=HTTPS Header always set Permissions-Policy: interest-cohort=() + +ErrorDocument 404 /404.html +AddDefaultCharset UTF-8 +FileETag MTime Size diff --git a/web/404.html b/web/404.html index a24448f41..326c73002 100644 --- a/web/404.html +++ b/web/404.html @@ -1,47 +1,27 @@ - - - - + + Leiningen: not found - - - Your Page Title Here :) - - - - - - - - - - - - - - - - - + + + + + - -
-

Sorry. Couldn't Find That Page!

-
- - +
+
+ +
+
+

Leiningen

+

Sorry. Couldn't Find That Page! You probably want + to go home?

+
+
- \ No newline at end of file + diff --git a/web/Makefile b/web/Makefile index 126c0a9be..ba1af18f1 100644 --- a/web/Makefile +++ b/web/Makefile @@ -1 +1,19 @@ -upload: ; rsync -r ./ philhag@leiningen.org:leiningen.org/ +DOCS=tutorial.html faq.html plugins.html profiles.html deploy.html + +upload: html + rsync -r ./ leiningen.org:leiningen.org/ + +html: $(DOCS) + +# we can't set the prerequisite properly because we used uppercase +# filenames for some reason in the markdown +%.html: + pandoc --template template.html --to html -o $@ \ + --metadata title="Leiningen $*" \ + ../doc/$(shell echo $* | tr '[:lower:]' '[:upper:]').md + +clean: ; rm $(DOCS) + +# TODO: css for code styles + +.PHONY: upload html diff --git a/web/_foot.html b/web/_foot.html new file mode 100644 index 000000000..a689250e7 --- /dev/null +++ b/web/_foot.html @@ -0,0 +1,11 @@ +

+ + + diff --git a/web/grench.html b/web/grench.html index ccb206b07..602719be7 100644 --- a/web/grench.html +++ b/web/grench.html @@ -1,36 +1,32 @@ - - - - - - - Grenchman - - + + Grenchman + + - - - - - - + + + - +
-
-

Grenchman

-
fast invocation of code over nREPL
+
+

Grenchman

+
fast invocation of code over nREPL

@@ -42,7 +38,7 @@
fast invocation of code over nREPL
running nREPL server you avoid JVM startup time, streamlining your development workflow. It includes its own repl client implementation - featuring full GNU + featuring full GNU Readline support as well as the ability to invoke Leiningen tasks.

@@ -53,10 +49,8 @@
fast invocation of code over nREPL
connect to it and run your code there.

Please report - issues on - GitHub or - the Leiningen mailing - list.

+ issues on + GitLab or on IRC.


-
+ diff --git a/web/index.html b/web/index.html index 98393204b..4e6254a6b 100644 --- a/web/index.html +++ b/web/index.html @@ -1,23 +1,17 @@ - - - - + + + Leiningen + + - - - Leiningen - - + - - - - @@ -28,13 +22,13 @@ - - - - + + + - + @@ -42,14 +36,15 @@
-
-

Leiningen

-
for automating Clojure projects without setting your hair on fire
+
+

Leiningen

+

for automating Clojure projects without setting + your hair on fire

@@ -72,87 +67,92 @@
for automating Clojure projects without setting your hair on fire

- -
-

Leiningen and Clojure require Java; ideally OpenJDK.

- + +
+

First check + your package + manager to see whether it includes Leiningen. If not, don't + worry; a manual install is easy.

+ +

Leiningen and Clojure require Java; ideally + OpenJDK. Get this from + your package manager, or download manually if you have to.

  1. Download the lein script (or on - Windows lein.bat)
  2. -
  3. Place it on your $PATH where your shell can find it (eg. ~/bin)
  4. -
  5. Set it to be executable (chmod a+x ~/bin/lein)
  6. + Windows lein.bat + if you don't use WSL) +
  7. Place it on your $PATH where your shell can find it (eg. /usr/local/bin/)
  8. +
  9. Set it to be executable (sudo chmod a+x /usr/local/bin/lein)
  10. Run it (lein) and it will download the self-install package
- -

You can check - your package - manager as well depending on your operating system.

-
+

- +
- diff --git a/web/stylesheets/base.css b/web/stylesheets/base.css index 42c79af10..0ecf8ab6a 100644 --- a/web/stylesheets/base.css +++ b/web/stylesheets/base.css @@ -3,7 +3,7 @@ * Copyright 2011, Dave Gamache * www.getskeleton.com * Free to use under the MIT license. -* http://www.opensource.org/licenses/mit-license.php +* https://www.opensource.org/licenses/mit-license.php * 8/17/2011 */ @@ -36,8 +36,6 @@ display: block; } body { line-height: 1; } - ol, ul { - list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, @@ -102,10 +100,7 @@ /* #Lists ================================================== */ - ul, ol { margin-bottom: 20px; } - ul { list-style: none outside; } - ol { list-style: decimal; } - ol, ul.square, ul.circle, ul.disc { margin-left: 30px; } + ul, ol { margin-bottom: 20px; margin-left: 30px; } ul.square { list-style: square outside; } ul.circle { list-style: circle outside; } ul.disc { list-style: disc outside; } diff --git a/web/stylesheets/layout.css b/web/stylesheets/layout.css index aff5b477e..a5c7474ce 100644 --- a/web/stylesheets/layout.css +++ b/web/stylesheets/layout.css @@ -3,7 +3,7 @@ * Copyright 2011, Dave Gamache * www.getskeleton.com * Free to use under the MIT license. -* http://www.opensource.org/licenses/mit-license.php +* https://www.opensource.org/licenses/mit-license.php * 8/17/2011 */ diff --git a/web/stylesheets/lein.css b/web/stylesheets/lein.css index cc085d432..a9f6de630 100644 --- a/web/stylesheets/lein.css +++ b/web/stylesheets/lein.css @@ -28,6 +28,10 @@ a:hover, a:focus { color: black; } +a.anchor { + text-decoration: none; + border-bottom: unset; +} p { text-align: justify; @@ -40,7 +44,7 @@ p#pitch { } pre, tt, kbd, code { - font-family: 'Inconsolata', 'Consolas', mono; + font-family: 'Inconsolata', 'Consolas', monospace; } #sample-project { diff --git a/web/stylesheets/skeleton.css b/web/stylesheets/skeleton.css index f36de832c..66f49d626 100644 --- a/web/stylesheets/skeleton.css +++ b/web/stylesheets/skeleton.css @@ -3,7 +3,7 @@ * Copyright 2011, Dave Gamache * www.getskeleton.com * Free to use under the MIT license. -* http://www.opensource.org/licenses/mit-license.php +* https://www.opensource.org/licenses/mit-license.php * 8/17/2011 */ diff --git a/web/template.html b/web/template.html new file mode 100644 index 000000000..b6c9b1be6 --- /dev/null +++ b/web/template.html @@ -0,0 +1,68 @@ + + + + $title$ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+

Leiningen

+

for automating Clojure projects without setting your hair on fire

+ +
+ +

+ +
+ ${body} +
+ +

+ + +
+ + + diff --git a/web/wiki/.gitignore b/web/wiki/.gitignore new file mode 100644 index 000000000..79ce752ad --- /dev/null +++ b/web/wiki/.gitignore @@ -0,0 +1 @@ +/index.cgi diff --git a/web/wiki/.htaccess b/web/wiki/.htaccess new file mode 100644 index 000000000..94b9040de --- /dev/null +++ b/web/wiki/.htaccess @@ -0,0 +1,9 @@ +Options +ExecCGI + +Header set Strict-Transport-Security "max-age=31536000" +Header set X-Frame-Options "DENY" +Header set X-XSS-Protection "1; mode=block" + +RewriteRule "^([-A-Za-z/]*)$" "/index.cgi?page=$1" + +ErrorDocument 404 /404.html diff --git a/web/wiki/404.html b/web/wiki/404.html new file mode 100644 index 000000000..e5eb8ff3c --- /dev/null +++ b/web/wiki/404.html @@ -0,0 +1,28 @@ + + + + Leiningen Wiki: not found + + + + + + + + + + + +
+
+ +
+
+

Leiningen

+

Sorry. Couldn't Find That Page! You probably want + to go home?

+
+
+ + diff --git a/web/wiki/Makefile b/web/wiki/Makefile new file mode 100644 index 000000000..64116d044 --- /dev/null +++ b/web/wiki/Makefile @@ -0,0 +1,2 @@ +upload: index.cgi .htaccess 404.html + rsync -rAv $^ leiningen@wiki.leiningen.org:wiki.leiningen.org/ diff --git a/web/wiki/index.cgi b/web/wiki/index.cgi new file mode 100755 index 000000000..dc91e91fe --- /dev/null +++ b/web/wiki/index.cgi @@ -0,0 +1,73 @@ +#!/home/leiningen/fennel +;; we don't have a great solution for the wiki right now; currently it's still +;; left on github because codeberg doesn't let you grant write access to their +;; wikis. for now we can just proxy the content from github and allow edits +;; to be done over git+SSH. + +(local head + " + + + Leiningen wiki: %s + + + + + + + + + + +
+
+
+ +
+
+

Leiningen wiki: %s

+") + +(local foot + "
+
+

To edit this wiki, clone the repo from + git@github.com:technomancy/leiningen.wiki.git and push your + changes there.

+
+") + +(fn url-for [page] + (let [url (.. "https://github.com/technomancy/leiningen/wiki/" page)] + ;; we REALLY don't want to let arbitrary input thru here when we shell out + (assert (not (page:match "[ $%(%)%.;&|]")) + "Illegal page; can't shell out to curl!") + url)) + +(fn get-body [page] + (let [curl (assert (io.popen (.. "curl --silent " (url-for page)))) + body (curl:read :*all)] + (assert (curl:close)) + body)) + +(fn query-string [] + (or (: (or (os.getenv "QUERY_STRING") "") :match "page=([-a-zA-Z/]+)") "")) + +(let [page (match (query-string) "" "Home" p p) + body (get-body (query-string)) + out (if (not= 0 (length body)) + [(head:format page page) + ;; this leaves a ton of unmatched closing divs but who cares + (body:match "
") + foot])] + (if out + (do + (print "content-encoding: utf8") + (print "content-type: text/html") + (print "") + (print (table.concat out "\n"))) + (do + (print "status: 404 not found") + (print "") + (print (with-open [f (io.open "404.html")] (f:read :*all))))))