Skip to content
Browse files

Merge branch '1.x'

Conflicts:
	README.md
	bin/lein
	bin/lein-pkg
	bin/lein.bat
	doc/PLUGINS.md
	pom.xml
	project.clj
	src/leiningen/compile.clj
	src/leiningen/trampoline.clj
	todo.org
  • Loading branch information...
2 parents ae84d2d + b8bdde8 commit 3b02d41e832bbeebfe39ecd7632fbbbdb8120dc6 @technomancy committed Nov 12, 2011
Showing with 815 additions and 506 deletions.
  1. +2 −0 .gitignore
  2. +8 −0 .travis.yml
  3. +42 −0 NEWS
  4. +54 −51 README.md
  5. +14 −4 bin/lein
  6. +24 −22 bin/lein-pkg
  7. +16 −9 bin/lein.bat
  8. +27 −7 doc/DEPLOY.md
  9. +32 −23 doc/PLUGINS.md
  10. +31 −20 doc/TUTORIAL.md
  11. +1 −1 doc/lein.1
  12. +3 −2 pom.xml
  13. +1 −1 project.clj
  14. +21 −5 sample.project.clj
  15. +3 −13 src/leiningen/classpath.clj
  16. +0 −1 src/leiningen/clean.clj
  17. +104 −82 src/leiningen/compile.clj
  18. +50 −19 src/leiningen/core.clj
  19. +5 −2 src/leiningen/deploy.clj
  20. +19 −16 src/leiningen/deps.clj
  21. +8 −4 src/leiningen/install.clj
  22. +15 −13 src/leiningen/interactive.clj
  23. +14 −8 src/leiningen/jar.clj
  24. +3 −1 src/leiningen/javac.clj
  25. +8 −7 src/leiningen/new.clj
  26. +24 −17 src/leiningen/plugin.clj
  27. +10 −9 src/leiningen/repl.clj
  28. +19 −12 src/leiningen/run.clj
  29. +14 −8 src/leiningen/search.clj
  30. +2 −2 src/leiningen/test.clj
  31. +15 −40 src/leiningen/trampoline.clj
  32. +4 −1 src/leiningen/uberjar.clj
  33. +1 −0 src/leiningen/util/file.clj
  34. +6 −6 src/leiningen/util/maven.clj
  35. +3 −4 src/leiningen/util/ns.clj
  36. +2 −4 src/leiningen/util/paths.clj
  37. +11 −4 test/leiningen/test/compile.clj
  38. +25 −0 test/leiningen/test/core.clj
  39. +32 −16 test/leiningen/test/deploy.clj
  40. +33 −22 test/leiningen/test/deps.clj
  41. +1 −1 test/leiningen/test/install.clj
  42. +3 −1 test/leiningen/test/jar.clj
  43. +1 −1 test/leiningen/test/javac.clj
  44. +4 −14 test/leiningen/test/plugin.clj
  45. +6 −1 test/leiningen/test/run.clj
  46. +2 −1 test_projects/dev-deps-only/project.clj
  47. +5 −1 test_projects/dev-deps-only/src/dev_deps_only/Junk.java
  48. +1 −1 test_projects/native/.gitignore
  49. +1 −0 test_projects/native/project.clj
  50. +1 −0 test_projects/sample/project.clj
  51. +2 −0 test_projects/sample/src/nom/nom/nom.clj
  52. +13 −29 todo.org
  53. +69 −0 zsh_completion.zsh
View
2 .gitignore
@@ -10,3 +10,5 @@ autodoc/
bin/nom
.lein-failures
/lein.man
+/scratch.clj
+.lein-deps-sum
View
8 .travis.yml
@@ -0,0 +1,8 @@
+---
+script: bin/lein self-install; bin/lein test
+branches:
+ only:
+ - 1.x
+ - master
+notifications:
+ irc: "irc.freenode.org#leiningen"
View
42 NEWS
@@ -1,5 +1,47 @@
Leiningen NEWS -- history of user-visible changes
+= 1.6.2 / 2011-11-11
+
+* Let run task work with main functions from Java classes.
+
+* Fix bug where exceptions would break interactive task.
+
+* Default to Clojure 1.3.0 for new projects.
+
+* Allow Leiningen home to exist inside project directory. (Heinz N. Gies)
+
+* Remove old versions of plugins when upgrading.
+
+* Add user-level :deploy-repositories list. (Michał Marczyk)
+
+* Fix a bug where class files from proxy objects weren't considered
+ part of the project. (Stephen Compall)
+
+* Make deps cause implicit clean to avoid AOT version mismatches.
+
+* Include Java source files in jar. (Nathan Marz)
+
+* Add separate :deploy-repositories list. (Chas Emerick)
+
+* Maintain order in repositories list. (Colin Jones)
+
+* Fix a bug where :omit-default-repos wouldn't skip Maven Central. (Chas Emerick)
+
+* Make deps extract native dependencies for all architectures, not just current.
+
+* Fix page count on search results.
+
+* Fix a bug where "lein plugin install" could skip dependencies.
+
+* Reimplement eval-in-project to use clojure.java.shell instead of Ant.
+
+* Separate LEIN_JVM_OPTS from JVM_OPTS.
+
+= 1.6.1.1 / 2011-09-06
+
+* Turn off workaround for Clojure's agent thread pool keeping the JVM alive
+ by default. Use :shutdown-agents in project.clj to enable it.
+
= 1.6.1 / 2011-07-06
* Allow alternate main namespace to be used during uberjar creation.
View
105 README.md
@@ -15,28 +15,21 @@ exercise in frustration. With Leiningen, you just write Clojure.
## Installation
-Leiningen bootstraps itself using the <tt>lein</tt> shell script;
-there is no separate 'install script'. It installs its dependencies
+Leiningen bootstraps itself using the `lein` shell script;
+there is no separate install script. It installs its dependencies
upon the first run on unix, so the first run will take longer.
-1. [Download the script](https://github.com/technomancy/leiningen/raw/stable/bin/lein).
-2. Place it on your path and chmod it to be executable.
-
-I like to place it in ~/bin, but it can go anywhere on the $PATH.
-
-On Windows most users can
-
-1. Download the Windows distribution
-[leiningen-1.5.2-win.zip](https://github.com/downloads/technomancy/leiningen/leiningen-1.5.2-win.zip)
-2. Unzip in a folder of choice.
-3. Include the "lein" directory in PATH.
+1. [Download the script](https://raw.github.com/technomancy/leiningen/stable/bin/lein).
+2. Place it on your path. (I like to use `~/bin`)
+3. Set it to be executable. (`chmod 755 ~/bin/lein`)
+On Windows most users can get
+[the batch file](https://raw.github.com/technomancy/leiningen/stable/bin/lein.bat).
If you have wget.exe or curl.exe already installed and in PATH, you
-can download either [the stable version
-lein.bat](https://github.com/technomancy/leiningen/raw/stable/bin/lein.bat),
-or [the development
-version](https://github.com/technomancy/leiningen/raw/master/bin/lein.bat)
-and use self-install.
+can just run `lein self-install`, otherwise get the standalone jar from the
+[downloads page](https://github.com/technomancy/leiningen/downloads).
+If you have [Cygwin](http://www.cygwin.com/) you should be able to use
+the shell script above rather than the batch file.
## Usage
@@ -55,48 +48,59 @@ project, but here are the commonly-used tasks:
$ lein install [NAME VERSION] # install a project
-Use <tt>lein help</tt> to see a complete list. <tt>lein help
-$TASK</tt> shows the usage for a specific one.
+ $ lein search ... # find recent jars for your project.clj dependencies
+
+Use `lein help` to see a complete list. `lein help $TASK` shows the
+usage for a specific one.
You can also chain tasks together in a single command by using commas:
$ lein clean, test foo.test-core, jar
Most tasks need to be run from somewhere inside a project directory to
-work, but some (<tt>new</tt>, <tt>help</tt>, <tt>version</tt>,
-<tt>plugin</tt>, and the two-argument version of <tt>install</tt>) may
-run from anywhere.
+work, but some (`new`, `help`, `version`, `plugin`, and the
+two-argument version of `install`) may run from anywhere.
-The install task places shell scripts in the <tt>~/.lein/bin</tt>
+The install task places shell scripts in the `~/.lein/bin`
directory for projects that include them, so if you want to take
-advantage of this, you should put it on your <tt>$PATH</tt>.
+advantage of this, you should put it on your `$PATH`.
## Configuration
-The <tt>project.clj</tt> file in the project root should look like this:
+The `project.clj` file in the project root should look like this:
+
+```clojure
+(defproject myproject "0.5.0-SNAPSHOT"
+ :description "A project for doing things."
+ :url "http://github.com/technomancy/myproject"
+ :dependencies [[org.clojure/clojure "1.2.1"]
+ [org.clojure/clojure-contrib "1.2.0"]]
+ :dev-dependencies [[lein-ring "0.4.5"]])
+```
- (defproject myproject "0.5.0-SNAPSHOT"
- :description "A project for doing things."
- :url "http://github.com/technomancy/myproject"
- :dependencies [[org.clojure/clojure "1.2.1"]
- [org.clojure/clojure-contrib "1.2.0"]]
- :dev-dependencies [[lein-ring "0.4.5"]])
+If you're looking for the most recent jar of one of your dependencies,
+use `lein search`.
-The <tt>lein new</tt> task generates a project skeleton with an
+The `lein new` task generates a project skeleton with an
appropriate starting point from which you can work. See the
[sample.project.clj](https://github.com/technomancy/leiningen/blob/stable/sample.project.clj)
file for a detailed listing of configuration options.
You can also have user-level configuration that applies for all
-projects. The <tt>~/.lein/init.clj</tt> file will be loaded every time
+projects. The `~/.lein/init.clj` file will be loaded every time
Leiningen launches; any arbitrary code may go there. This code is
executed inside Leiningen itself, not in your project. Set the
-<tt>:repl-init</tt> key in project.clj to point to a namespace if
+`:repl-init` key in project.clj to point to a namespace if
you want code executed inside your project.
-You can also manage your plugins with the <tt>plugin</tt> task. Use
-the same arguments you would put in the Leiningen :dev-dependencies if
-you were only using the plugin on a single project.
+## Leiningen Plugins
+
+Leiningen supports plugins. See [the plugins wiki
+page](https://github.com/technomancy/leiningen/wiki/Plugins) for a
+full list. If a plugin is needed for successful test or build runs,
+(such as lein-tar) then it should be added to `:dev-dependencies` in
+project.clj, but if it's for your own convenience (such as
+swank-clojure) then it should be added using the `plugin` task:
$ lein plugin install lein-clojars "0.6.0"
@@ -156,7 +160,7 @@ See the plugin task's help for more information.
**Q:** I want to hack two projects in parallel, but it's annoying to switch between them.
**A:** Use a feature called _checkout dependencies_. If you create a
- directory called <tt>checkouts</tt> in your project root and symlink
+ directory called `checkouts` in your project root and symlink
some other project roots into it, Leiningen will allow you to hack
on them in parallel. That means changes in the dependency will be
visible in the main project without having to go through the whole
@@ -174,7 +178,7 @@ See the plugin task's help for more information.
**Q:** What does java.lang.NoSuchMethodError: clojure.lang.RestFn.<init>(I)V mean?
**A:** It means you have some code that was AOT (ahead-of-time)
compiled with a different version of Clojure than the one you're
- currently using. If it persists after running <tt>lein clean</tt> then it
+ currently using. If it persists after running `lein clean` then it
is a problem with your dependencies. Note that for
your own project that AOT compilation in Clojure is much less
important than it is in other languages. There are a few
@@ -185,12 +189,12 @@ See the plugin task's help for more information.
**Q:** I'm behind an HTTP proxy; how can I fetch my dependencies?
**A:** Currently you need to configure the underlying Maven library by
- creating <tt>~/.m2/settings.xml</tt> as explained in the
+ creating `~/.m2/settings.xml` as explained in the
[Maven guide](http://maven.apache.org/guides/mini/guide-proxies.html).
**Q:** What can be done to speed up launch?
**A:** The main delay involved in Leiningen comes from starting the
- JVM. Launching "lein interactive" will give you an interactive
+ JVM. Launching `lein interactive` will give you an interactive
session so you can run many tasks against the same process instead
of launching a new one every time. Depending on your editor you may
also be able to take advantage of its Clojure integration. (See
@@ -204,15 +208,14 @@ See the plugin task's help for more information.
launch a client JVM, but this only works on 32-bit Hotspot. If you
are on a 64-bit machine you can still use a client JVM if you
install 32-bit packages; on Debian try ia32-sun-java6-bin. Once
- you've installed it, run <tt>sudo update-java-alternatives -s
- ia32-java-6-sun</tt>.
+ you've installed it, run `sudo update-java-alternatives -s ia32-java-6-sun`.
**Q:** I don't have access to stdin inside my project.
**A:** There's a bug in the Ant library that Leiningen uses to spawn
new processes that blocks access to console input. This means that
- functions like <tt>read-line</tt> will not work as expected in most
- contexts, though the <tt>repl</tt> task necessarily includes a
- workaround. You can also use the <tt>trampoline</tt> task to
+ functions like `read-line` will not work as expected in most
+ contexts, though the `repl` task necessarily includes a
+ workaround. You can also use the `trampoline` task to
launch your project's JVM after Leiningen's has exited rather than
launching it as a subprocess
@@ -244,15 +247,15 @@ mailing list and mailing a SASE.
You don't need to "build" Leiningen per se, but when you're using a
checkout you will need to get its dependencies in place. In most cases
-a <tt>lein self-install</tt> will usually get you what you
+a `lein self-install` will usually get you what you
need. However, this will occasionally fail for very new SNAPSHOT
versions since the standalone jar will not have been uploaded yet.
Alternatively if you have a copy of an older Leiningen version around
(at least 1.1.0, installed as lein-stable, for example), then you can
-run "lein-stable deps" in your checkout. If Leiningen's dependencies
+run `lein-stable deps` in your checkout. If Leiningen's dependencies
change it will be necessary to remove the lib/ directory entirely
-before running "lein deps" again. (This is not necessary for most
+before running `lein deps` again. (This is not necessary for most
projects, but Leiningen has unique bootstrapping issues when working
on itself.)
@@ -261,7 +264,7 @@ You can also use Maven, just for variety's sake:
$ mvn dependency:copy-dependencies
$ mv target/dependency lib
-Symlink bin/lein from your checkout into a location on the $PATH. The
+Symlink `bin/lein` from your checkout into a location on the $PATH. The
script can figure out when it's being called from inside a checkout
and use the checkout rather than the self-install uberjar if necessary.
View
18 bin/lein
@@ -33,7 +33,12 @@ do
done
if [ "$LEIN_HOME" = "" ]; then
+ if [ -d "$PWD/.lein" ] && [ "$PWD" != "$HOME" ]; then
+ echo "Leiningen is running in bundled mode."
+ LEIN_HOME="$PWD/.lein"
+ else
LEIN_HOME="$HOME/.lein"
+ fi
fi
DEV_PLUGINS="$(ls -1 lib/dev/*jar 2> /dev/null)"
@@ -67,8 +72,8 @@ unique_user_plugins () {
LEIN_PLUGIN_PATH="$(echo "$DEV_PLUGINS" | tr \\n :)"
LEIN_USER_PLUGIN_PATH="$(echo "$(unique_user_plugins)" | tr \\n :)"
-CLASSPATH="$CLASSPATH:$LEIN_PLUGIN_PATH:$LEIN_USER_PLUGIN_PATH:test/:src/"
-LEIN_JAR="$HOME/.lein/self-installs/leiningen-$LEIN_VERSION-standalone.jar"
+CLASSPATH="$CLASSPATH:$LEIN_PLUGIN_PATH:$LEIN_USER_PLUGIN_PATH:test/:src/:resources/"
+LEIN_JAR="$LEIN_HOME/self-installs/leiningen-$LEIN_VERSION-standalone.jar"
CLOJURE_JAR="$HOME/.m2/repository/org/clojure/clojure/1.2.1/clojure-1.2.1.jar"
NULL_DEVICE=/dev/null
@@ -133,6 +138,11 @@ export JVM_OPTS=${JVM_OPTS:-"$JAVA_OPTS"}
# If you're packaging this for a package manager (.deb, homebrew, etc)
# you need to remove the self-install and upgrade functionality.
if [ "$1" = "self-install" ]; then
+ if [ -r "$LEIN_JAR" ]; then
+ echo "The self-install jar already exists at $LEIN_JAR."
+ echo "If you wish to re-download, delete it and rerun \"$0 self-install\"."
+ exit 1
+ fi
echo "Downloading Leiningen now..."
LEIN_DIR=`dirname "$LEIN_JAR"`
mkdir -p "$LEIN_DIR"
@@ -174,7 +184,7 @@ elif [ "$1" = "upgrade" ]; then
$HTTP_CLIENT "$TARGET" "$LEIN_SCRIPT_URL" \
&& mv "$TARGET" "$SCRIPT" \
&& chmod +x "$SCRIPT" \
- && echo && $SCRIPT self-install && echo && echo "Now running" `$SCRIPT version`
+ && echo && "$SCRIPT" self-install && echo && echo "Now running" `$SCRIPT version`
exit $?;;
*)
echo "Aborted."
@@ -215,7 +225,7 @@ else
# Test to see if rlwrap supports custom quote chars
rlwrap -m -q '"' echo "hi" > /dev/null 2>&1
if [ $? -eq 0 ]; then
- RLWRAP="$RLWRAP -m -q '\"'"
+ RLWRAP="$RLWRAP -r -m -q '\"'"
fi
fi
fi
View
46 bin/lein-pkg 100755 → 100644
@@ -4,7 +4,7 @@
# It has all the cross-platform stuff stripped out as well as the
# logic for running from checkouts and self-upgrading.
-LEIN_VERSION="1.6.1"
+LEIN_VERSION="1.6.2"
export LEIN_VERSION
if [ `whoami` = "root" ] && [ "$LEIN_ROOT" = "" ]; then
@@ -28,7 +28,15 @@ done
# Support $JAVA_OPTS for backwards-compatibility.
JVM_OPTS=${JVM_OPTS:-"$JAVA_OPTS"}
JAVA_CMD=${JAVA_CMD:-"java"}
-LEIN_HOME=${LEIN_HOME:-"$HOME/.lein"}
+
+if [ "$LEIN_HOME" = "" ]; then
+ if [ -d "$PWD/.lein" ] && [ "$PWD" != "$HOME" ]; then
+ echo "Leiningen is running in bundled mode."
+ LEIN_HOME="$PWD/.lein"
+ else
+ LEIN_HOME="$HOME/.lein"
+ fi
+fi
DEV_PLUGINS="$(ls -1 lib/dev/*jar 2> /dev/null)"
USER_PLUGINS="$(ls -1 "$LEIN_HOME"/plugins/*jar 2> /dev/null)"
@@ -61,24 +69,16 @@ unique_user_plugins () {
LEIN_PLUGIN_PATH="$(echo "$DEV_PLUGINS" | tr \\n :)"
LEIN_USER_PLUGIN_PATH="$(echo "$(unique_user_plugins)" | tr \\n :)"
-CLASSPATH="$CLASSPATH:$LEIN_PLUGIN_PATH:$LEIN_USER_PLUGIN_PATH:test/:src/"
-LEIN_JAR="$HOME/.lein/self-installs/leiningen-$LEIN_VERSION-standalone.jar"
-CLOJURE_JAR="/usr/share/java/clojure-1.2.jar:/usr/share/java/asm3.jar"
+CLASSPATH="$CLASSPATH:$LEIN_PLUGIN_PATH:$LEIN_USER_PLUGIN_PATH:test/:src/:resources/"
+CLOJURE_JAR="/usr/share/java/clojure-1.2.jar:/usr/share/java/asm3.jar:/usr/share/java/asm3-commons.jar"
NULL_DEVICE=/dev/null
# apply context specific CLASSPATH entries
-if [ -f .classpath ]; then
- CLASSPATH="`cat .classpath`:$CLASSPATH"
-fi
-
-# normalize $0 on certain BSDs
-if [ "$(dirname "$0")" = "." ]; then
- SCRIPT="$(which $(basename "$0"))"
-else
- SCRIPT="$0"
+if [ -f .lein-classpath ]; then
+ CLASSPATH="`cat .lein-classpath`:$CLASSPATH"
fi
-SHARE_JARS="ant ant-launcher classworlds clojure-1.2 \
+SHARE_JARS="ant ant-launcher classworlds clojure-1.2 clojure-contrib \
lucene-memory maven-ant-tasks maven-artifact maven-artifact-manager \
maven-error-diagnostics maven-model maven-settings maven-project maven-profile \
maven-repository-metadata plexus-container-default-alpha plexus-interpolation \
@@ -89,8 +89,10 @@ for JAR in $SHARE_JARS; do
CLASSPATH="$CLASSPATH":"/usr/share/java/$JAR.jar"
done
-# Keep already-packaged Leiningen jar off the classpath during packaging.
-if [ ! -r src/leiningen/core.clj ]; then
+# Do not use installed leiningen jar during self-compilation
+if ! { [ "$1" = "compile" ] &&
+ grep -qsE 'defproject leiningen[[:space:]]+"[[:digit:].]+"' \
+ project.clj ;}; then
CLASSPATH="$CLASSPATH":/usr/share/java/leiningen-$LEIN_VERSION.jar
fi
@@ -104,25 +106,25 @@ if ([ "$1" = "repl" ] || [ "$1" = "interactive" ] || [ "$1" = "int" ]) &&
[ -z $INSIDE_EMACS ] && [ "$TERM" != "dumb" ]; then
which rlwrap > /dev/null
if [ $? -eq 0 ]; then
- RLWRAP="rlwrap -m -q '\"'" # custom quote chars
+ RLWRAP="rlwrap -r -m -q '\"'" # custom quote chars
fi
fi
if [ "$1" = "trampoline" ]; then
TRAMPOLINE_FILE="/tmp/lein-trampoline-$$"
- $JAVA_CMD -Xbootclasspath/a:"$CLOJURE_JAR" -client $JVM_OPTS \
+ $JAVA_CMD -Xbootclasspath/a:"$CLOJURE_JAR" -client $LEIN_JVM_OPTS \
-Dleiningen.original.pwd="$ORIGINAL_PWD" \
-Dleiningen.trampoline-file=$TRAMPOLINE_FILE -cp "$CLASSPATH" \
clojure.main -e "(use 'leiningen.core)(-main)" \
$NULL_DEVICE "$@"
if [ -r $TRAMPOLINE_FILE ]; then
TRAMPOLINE="$(cat $TRAMPOLINE_FILE)"
rm $TRAMPOLINE_FILE
- exec sh -c "TRAMPOLINE"
+ exec sh -c "$TRAMPOLINE"
fi
else
- exec $RLWRAP $JAVA_CMD -Xbootclasspath/a:"$CLOJURE_JAR" -client $JVM_OPTS \
- -Dleiningen.original.pwd="$ORIGINAL_PWD" \
+ exec $RLWRAP $JAVA_CMD -Xbootclasspath/a:"$CLOJURE_JAR" -client \
+ $LEIN_JVM_OPTS -Dleiningen.original.pwd="$ORIGINAL_PWD" \
-cp "$CLASSPATH" clojure.main -e "(use 'leiningen.core)(-main)" \
$NULL_DEVICE "$@"
fi
View
25 bin/lein.bat
@@ -10,14 +10,6 @@ if "%LEIN_VERSION:~-9%" == "-SNAPSHOT" (
set SNAPSHOT=NO
)
-:: LEIN_JAR and LEIN_HOME variables can be set manually.
-
-if "x%LEIN_HOME%" == "x" set LEIN_HOME=%USERPROFILE%\.lein
-if "x%LEIN_JAR%" == "x" set LEIN_JAR="!LEIN_HOME!\self-installs\leiningen-!LEIN_VERSION!-standalone.jar"
-
-if "%1" == "self-install" goto SELF_INSTALL
-if "%1" == "upgrade" goto NO_UPGRADE
-
set ORIGINAL_PWD=%CD%
:: If ORIGINAL_PWD ends with a backslash (such as C:\),
:: we need to escape it with a second backslash.
@@ -26,6 +18,21 @@ if "%ORIGINAL_PWD:~-1%x" == "\x" set "ORIGINAL_PWD=%ORIGINAL_PWD%\"
call :FIND_DIR_CONTAINING_UPWARDS project.clj
if "%DIR_CONTAINING%" neq "" cd "%DIR_CONTAINING%"
+:: LEIN_JAR and LEIN_HOME variables can be set manually.
+
+if "x%LEIN_HOME%" == "x" (
+ if exist "%CD%\.lein" (
+ if /I NOT %CD%==%USERPROFILE% echo Running in bundled mode.
+ set LEIN_HOME=%CD%\.lein
+ ) else (
+ set LEIN_HOME=%USERPROFILE%\.lein
+ )
+)
+
+if "x%LEIN_JAR%" == "x" set LEIN_JAR="!LEIN_HOME!\self-installs\leiningen-!LEIN_VERSION!-standalone.jar"
+
+if "%1" == "self-install" goto SELF_INSTALL
+if "%1" == "upgrade" goto NO_UPGRADE
set DEV_PLUGINS="
for %%j in (".\lib\dev\*.jar") do (
@@ -34,7 +41,7 @@ for %%j in (".\lib\dev\*.jar") do (
set DEV_PLUGINS=!DEV_PLUGINS!"
call :BUILD_UNIQUE_USER_PLUGINS
-set CLASSPATH="%CLASSPATH%";%DEV_PLUGINS%;%UNIQUE_USER_PLUGINS%;test;src
+set CLASSPATH="%CLASSPATH%";%DEV_PLUGINS%;%UNIQUE_USER_PLUGINS%;test;src;resources
:: Apply context specific CLASSPATH entries
set CONTEXT_CP=
View
34 doc/DEPLOY.md
@@ -44,11 +44,26 @@ The private server will need to be added to the <tt>:repositories</tt>
listing in project.clj. Archiva and Nexus offer separate repositories
for snapshots and releases, so you'll want two entries for them:
- :repositories {"snapshots" {:url "http://blueant.com/archiva/snapshots"
- :username "milgrim" :password "locative.1"}
- "releases" "http://blueant.com/archiva/internal"}
+```clj
+:repositories {"snapshots" {:url "http://blueant.com/archiva/snapshots"
+ :username "milgrim" :password "locative.1"}
+ "releases" "http://blueant.com/archiva/internal"}
+```
-Private repositories need authentication credentials. You'll need to
+If you are are deploying to a repository that is _only_ used for deployment
+and never for dependency resolution, then it should be specified in a
+`:deploy-repositories` slot instead of included in the more general-purpose
+`:repositories` map; the former is checked by `lein deploy` before the latter.
+Deployment-only repositories useful across a number of locally developed
+projects may also be specified in the `settings` map in `~/.lein/init.clj`:
+
+```clj
+(def settings {:deploy-repositories { ... }})
+```
+
+### Authentication
+
+Private repositories often need authentication credentials. You'll need to
provide either a <tt>:username</tt>/<tt>:password</tt> combination or
a <tt>:private-key</tt> location with or without a
<tt>:passphrase</tt>. If you want to avoid putting sensitive
@@ -57,12 +72,16 @@ entry above, you can store authentication information in
<tt>~/.lein/init.clj</tt> as a <tt>leiningen-auth</tt> map keyed off
the repository's URL:
- (def leiningen-auth {"http://localhost:8080/archiva/repository/internal/"
- {:username "milgrim" :password "locative.2"}})
+```clj
+(def leiningen-auth {"http://localhost:8080/archiva/repository/internal/"
+ {:username "milgrim" :password "locative.2"}})
+```
This also allows different users using the same checkout to upload
using different credentials.
+### Deployment
+
Once you've set up a private repository and configured project.clj
appropriately, you can deploy to it:
@@ -72,4 +91,5 @@ If the project's current version is a SNAPSHOT, it will deploy to the
<tt>snapshots</tt> repository; otherwise it will go to
<tt>releases</tt>. The <tt>deploy</tt> task also takes a repository
name as an argument that will be looked up in the
-<tt>:repositories</tt> map if you want to override this.
+<tt>:deploy-repositories</tt> and <tt>:repositories</tt> maps
+if you want to override this.
View
55 doc/PLUGINS.md
@@ -29,24 +29,11 @@ a project subprocess.
Some tasks may only be run in the context of a project. For tasks like
this, name the first argument <tt>project</tt>. Leiningen will inspect
-the argument list and pass in the current project if needed.
-
-Some tasks can be run inside a project or outside, but would benefit
-from having the project argument if they're run from a project. For
-these, name the first argument something like <tt>project-or-foo</tt>,
-and it will be passed the project argument when appropriate.
-
-The project is a map which is based on the project.clj file, but it
-also has :name, :group, :version, and :root keys added in. If you want
-it to take parameters from the command-line invocation, you can make
-the function take more arguments.
-
-Note that Leiningen is an implied dependency of all plugins; you
-should not explicitly list it in the project.clj file. You also don't
-need to list Clojure, but you will be locked into using the same
-version of Clojure that Leiningen is using. For Leiningen 1.x, a
-dependency on Clojure Contrib is also implied, though this is gone in
-2.0.
+the argument list and pass in the current project if needed. The
+project is a map which is based on the project.clj file, but it also
+has :name, :group, :version, and :root keys added in. If you want it
+to take parameters from the command-line invocation, you can make the
+function take more arguments.
The "lein help" task will display the first line of the task
function's docstring as a summary. Then "lein help $TASK" will use
@@ -119,13 +106,15 @@ altering the return value, only running the function conditionally,
etc. The add-hook function takes a var of the task it's meant to apply
to and a function to perform the wrapping:
- (use 'robert.hooke)
+```clj
+(use 'robert.hooke)
- (defn skip-integration-hook [task & args]
- (binding [clojure.test/test-var (test-var-skip :integration)]
- (apply task args)))
+(defn skip-integration-hook [task & args]
+ (binding [clojure.test/test-var (test-var-skip :integration)]
+ (apply task args)))
- (add-hook #'leiningen.test/test skip-integration-hook)
+(add-hook #'leiningen.test/test skip-integration-hook)
+```
Hooks compose, so be aware that your hook may be running inside
another hook. To take advantage of your hooks functionality, projects
@@ -151,6 +140,26 @@ itself, add a '.lein-classpath' file a project's root. Its contents
will be prepended to Leiningen's classpath when Leiningen is invoked
upon that project.
+## Clojure Version
+
+Note that Leiningen is an implied dependency of all plugins; you don't
+need to explicitly list it in the project.clj file. You also don't
+need to list Clojure or Contrib, but you will be locked into using the
+same version of Clojure that Leiningen is using.
+
+Versions of Leiningen prior to 1.2.0 used Clojure 1.1, while the rest
+of the 1.x line uses Clojure 1.2. Leiningen 2.0 will use Clojure 1.3.
+If you need to use a different version of Clojure from within a
+Leiningen plugin, you can use `eval-in-project` with a dummy project
+argument:
+
+```clj
+(eval-in-project {:local-repo-classpath true
+ :dependencies '[[org.clojure/clojure "1.3.0"]]
+ :native-path "/tmp" :root "/tmp" :compile-path "/tmp"}
+ '(println "hello from" *clojure-version*))
+```
+
## Lancet
If your plugins need to do a fair amount of filesystem-y things, you
View
51 doc/TUTORIAL.md
@@ -59,9 +59,11 @@ repositories for you.
$ cat project.clj
- (defproject myproject "1.0.0-SNAPSHOT"
- :description "FIXME: write description"
- :dependencies [[org.clojure/clojure "1.2.1"]])
+```clj
+(defproject myproject "1.0.0-SNAPSHOT"
+ :description "FIXME: write description"
+ :dependencies [[org.clojure/clojure "1.2.1"]])
+```
Fill in the :description with a short paragraph so that your project
will show up in search results once you publish it. At some point
@@ -140,8 +142,7 @@ instead of a single version:
[org.clojure/clojure "[1.1,1.2]"] ; <= will match 1.1.0 through 1.2.0.
-See [Maven's version range
-specification](http://maven.apache.org/plugins/maven-enforcer-plugin/rules/versionRanges.html)
+See [Maven's version range specification](http://j.mp/twc713)
for details. Don't do this unless you have manually confirmed that it
works with each of those versions though. You can't assume that your
dependencies will use semantic versions; some projects even introduce
@@ -206,14 +207,18 @@ Rather than running your whole suite or just a few namespaces at a
time, you can run a subset of your tests using test selectors. To do
this, you attach metadata to various deftests.
- (deftest ^{:integration true} network-heavy-test
- (is (= [1 2 3] (:numbers (network-operation)))))
+```clj
+(deftest ^{:integration true} network-heavy-test
+ (is (= [1 2 3] (:numbers (network-operation)))))
+```
Then add a :test-selectors map to project.clj:
- :test-selectors {:default (fn [v] (not (:integration v)))
- :integration :integration
- :all (fn [_] true)}
+```clj
+:test-selectors {:default (fn [v] (not (:integration v)))
+ :integration :integration
+ :all (fn [_] true)}
+```
Now if you run "lein test" it will only run deftests that don't have
:integration metadata, while "lein test :integration" will only run
@@ -298,12 +303,14 @@ nontechnical users. For this to work you'll need to specify a
namespace as your :main in project.clj. By this point our project.clj
file should look like this:
- (defproject myproject "1.0.0-SNAPSHOT"
- :description "This project is MINE."
- :dependencies [[org.clojure/clojure "1.2.0"]
- [org.apache.lucene/lucene-core "3.0.2"]
- [lancet "1.0.0"]]
- :main myproject.core)
+```clj
+(defproject myproject "1.0.0-SNAPSHOT"
+ :description "This project is MINE."
+ :dependencies [[org.clojure/clojure "1.2.0"]
+ [org.apache.lucene/lucene-core "3.0.2"]
+ [lancet "1.0.0"]]
+ :main myproject.core)
+```
The namespace you specify will need to contain a <tt>-main</tt>
function that will get called when your standalone jar is run. This
@@ -312,11 +319,13 @@ namespace should have a <tt>(:gen-class)</tt> declaration in the
passed the command-line arguments. Let's try something simple in
src/myproject/core.clj:
- (ns myproject.core
- (:gen-class))
+```clj
+(ns myproject.core
+ (:gen-class))
- (defn -main [& args]
- (println "Welcome to my project! These are your args:" args))
+(defn -main [& args]
+ (println "Welcome to my project! These are your args:" args))
+```
Now we're ready to generate your uberjar:
@@ -367,8 +376,10 @@ project.clj, Leiningen automatically generates a simple shell script
wrapper when you create your jar file. However, if you need more
control you can provide a map instead:
+```clj
:shell-wrapper {:main myproject.core
:bin "bin/myproject"}
+```
Normally the shell wrapper will invoke the -main function in your
project's :main namespace, but specifying this option triggers AOT for
View
2 doc/lein.1
@@ -1,4 +1,4 @@
-./"to render: groff -Tascii -man doc/lein.1 > lein.man"
+.\"to render: groff -Tascii -man doc/lein.1 > lein.man"
.TH LEININGEN 1 "2011 June 30"
.SH NAME
lein \- Automate Clojure projects
View
5 pom.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>leiningen</groupId>
<artifactId>leiningen</artifactId>
@@ -82,7 +83,7 @@
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-ant-tasks</artifactId>
- <version>2.0.10</version>
+ <version>2.1.3</version>
<exclusions>
<exclusion>
<artifactId>ant</artifactId>
View
2 project.clj
@@ -12,6 +12,6 @@
[lancet "1.0.1"]
[jline "0.9.94" :exclusions [junit]]
[robert/hooke "1.1.2"]
- [org.apache.maven/maven-ant-tasks "2.0.10" :exclusions [ant]]]
+ [org.apache.maven/maven-ant-tasks "2.1.3" :exclusions [ant]]]
:disable-implicit-clean true
:eval-in-leiningen true)
View
26 sample.project.clj
@@ -116,9 +116,9 @@
:repl-retry-limit 1000
;; Emit warnings on all reflection calls.
:warn-on-reflection true
- ;; Set this in order to only use the :repositories you list below. Note that
- ;; a bug in maven-ant-tasks prevents Leiningen from excluding Maven Central,
- ;; so in effect this simply omits Clojars.
+ ;; Set this in order to only use the :repositories you list below. Note that,
+ ;; if any artifacts are not found, Maven Central will still be reported to
+ ;; have been checked, even though it was not.
:omit-default-repositories true
:repositories {"java.net" "http://download.java.net/maven/2"
"sonatype"
@@ -138,9 +138,16 @@
:username "milgrim" :password "locative.1"}
"releases" {:url "http://blueant.com/archiva/internal"
:username "milgrim" :password "locative.1"}}
+ ;; 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"
+ :username "milgrim" :password "locative.1"}
+ "snapshots" "http://blueant.com/archiva/internal/snapshots"}
;; If you'd rather use a different directory structure, you can set these.
:source-path "src/main/clojure"
- :library-path "target/dependency"
+ :compile-path "target/classes" ; for .class files
+ :library-path "target/dependency" ; for .jar files
:test-path "src/test/clojure"
:resources-path "src/main/resource" ; non-code files included in classpath/jar
:dev-resources-path "src/test/resource" ; added to dev classpath but not jar
@@ -166,7 +173,16 @@
;; You can set JVM-level options here.
:jvm-opts ["-Xmx1g"]
;; If your project is a Leiningen plugin, set this to skip the subprocess step
- :eval-in-leiningen false)
+ :eval-in-leiningen false
+ ;; Leiningen includes a workaround for a problem with Clojure's
+ ;; agent thread pool. If you see RejectedExecutionException using
+ ;; futures or agents, you may be working with a plugin that doesn't
+ ;; take this workaround into account yet--see the "Threads" section
+ ;; of doc/PLUGINS.md. This key will disable Leiningen's workaround.
+ ;; It may cause some other plugins to fail to exit when they finish.
+ :skip-shutdown-agents true
+ ;; Set parent for working with in a multi-module maven project
+ :parent [org.example/parent "0.0.1" :relative-path "../parent/pom.xml"])
;; You can use Robert Hooke to modify behaviour of any task function,
;; but the prepend-tasks function is shorthand that is more convenient
View
16 src/leiningen/classpath.clj
@@ -1,11 +1,10 @@
(ns leiningen.classpath
"Print the classpath of the current project."
(:use [leiningen.core :only [read-project no-dev?]]
- [leiningen.deps :only [find-jars]]
+ [leiningen.deps :only [find-deps-files]]
[leiningen.util.paths :only [leiningen-home]]
[clojure.java.io :only [file]]
- [clojure.string :only [join]])
- (:import (org.apache.tools.ant.types Path)))
+ [clojure.string :only [join]]))
(defn- read-dependency-project [dep]
(let [project (.getAbsolutePath (file dep "project.clj"))]
@@ -35,15 +34,6 @@
:when (re-find #"\.jar$" (.getName jar))]
(.getAbsolutePath jar)))
-;; TODO: move to lancet?
-(defn ^:internal make-path
- "Constructs an ant Path object from Files and strings."
- [& paths]
- (let [ant-path (Path. nil)]
- (doseq [path paths]
- (.addExisting ant-path (Path. nil (str path))))
- ant-path))
-
(defn get-classpath
"Answer a list of classpath entries for PROJECT."
[project]
@@ -55,7 +45,7 @@
(:resources-path project)]
(:extra-classpath-dirs project)
(checkout-deps-paths project)
- (find-jars project)
+ (find-deps-files project)
(if-not (no-dev?)
(user-plugins))))
View
1 src/leiningen/clean.clj
@@ -20,6 +20,5 @@
Set :extra-files-to-clean in project.clj to delete other files. Dependency
jars are not deleted; run deps task to delete all jars and get fresh ones."
[project]
- (println "Cleaning up.")
(doseq [f (files-to-clean project)]
(delete-file-recursively f :silently)))
View
186 src/leiningen/compile.clj
@@ -1,26 +1,20 @@
(ns leiningen.compile
"Compile Clojure source into .class files."
- (:use [leiningen.deps :only [deps find-jars]]
+ (:use [leiningen.deps :only [deps find-deps-files]]
[leiningen.core :only [defdeprecated user-settings *interactive?*]]
[leiningen.javac :only [javac]]
- [leiningen.classpath :only [make-path get-classpath]]
- [clojure.java.io :only [file resource reader]]
+ [leiningen.classpath :only [get-classpath-string]]
+ [clojure.java.io :only [file resource reader copy]]
[leiningen.util.ns :only [namespaces-in-dir]])
- (:require [leiningen.util.paths :as paths]
- [lancet.core :as lancet])
+ (:require [leiningen.util.paths :as paths])
(:refer-clojure :exclude [compile])
- (:import (java.io PushbackReader)
- (org.apache.tools.ant.taskdefs Java)
- (org.apache.tools.ant.types ZipFileSet)
- (java.lang.management ManagementFactory)
- (java.util.regex Pattern)
- (org.apache.tools.ant.types Environment$Variable)))
+ (:import (java.io PushbackReader)))
(declare compile)
-(def *silently* false)
+(def ^{:dynamic true} *silently* false)
-(def *skip-auto-compile* false)
+(def ^{:dynamic true} *skip-auto-compile* false)
(defn- regex?
"Returns true if we have regex class"
@@ -42,6 +36,11 @@
n))
nses)))
+
+(defn- compile-main? [{:keys [main source-path] :as project}]
+ (and main (not (:skip-aot (meta main)))
+ (.exists (file source-path (paths/ns->path main)))))
+
(defn compilable-namespaces
"Returns a seq of the namespaces that are compilable, regardless of whether
their class files are present and up-to-date."
@@ -52,7 +51,7 @@
nses (if (= :all nses)
(namespaces-in-dir (:source-path project))
(find-namespaces-by-regex project nses))]
- (if (and (:main project) (not (:skip-aot (meta (:main project)))))
+ (if (compile-main? project)
(conj nses (:main project))
nses)))
@@ -70,6 +69,8 @@
(.lastModified class-file)))))
(compilable-namespaces project)))
+ ;; eval-in-project
+
(defdeprecated get-os paths/get-os)
(defdeprecated get-os paths/get-arch)
@@ -79,11 +80,26 @@
"NUL"
"/dev/null")))
-(defn- get-jvm-args [project]
- (remove empty?
- `(~@(when-let [opts (System/getenv "JVM_OPTS")] [opts])
- ~@(:jvm-opts project)
- ~@(:jvm-opts (user-settings)))))
+(defn- as-str [x]
+ (if (instance? clojure.lang.Named x)
+ (name x)
+ (str x)))
+
+(defn- d-property [[k v]]
+ (format "-D%s=%s" (as-str k) v))
+
+(defn ^{:internal true} get-jvm-args [project]
+ (let [native-arch-path (paths/native-arch-path project)]
+ `(~@(let [opts (System/getenv "JVM_OPTS")]
+ (when (seq opts) [opts]))
+ ~@(:jvm-opts project)
+ ~@(:jvm-opts (user-settings))
+ ~@(map d-property {:clojure.compile.path (:compile-path project)
+ (str (:name project) ".version") (:version project)
+ :clojure.debug (boolean (or (System/getenv "DEBUG")
+ (:debug project)))})
+ ~@(when (and native-arch-path (.exists native-arch-path))
+ [(d-property [:java-library-path native-arch-path])]))))
(defn- injected-forms []
(with-open [rdr (-> "robert/hooke.clj" resource reader PushbackReader.)]
@@ -104,34 +120,70 @@
;; non-daemon threads will prevent process from exiting;
;; see http://tinyurl.com/2ueqjkl
(finally
- (when-not (or (= "1.5" (System/getProperty
+ (when (and ~(:shutdown-agents project false)
+ (not= "1.5" (System/getProperty
"java.specification.version"))
- ~*interactive?*)
+ ~(not *interactive?*))
(shutdown-agents)))))]
;; work around java's command line handling on windows
;; http://bit.ly/9c6biv This isn't perfect, but works for what's
;; currently being passed; see
;; http://www.perlmonks.org/?node_id=300286 for some of the
;; landmines involved in doing it properly
- (if (and (= (paths/get-os) :windows) java)
+ (if (and (= (paths/get-os) :windows) (not (:eval-in-leiningen project)))
(pr-str (pr-str form))
- (prn-str form))))
+ (pr-str form))))
-(defn prep [project skip-auto-compile]
- (when (and (not (or *skip-auto-compile* skip-auto-compile))
- (empty? (.list (file (:compile-path project)))))
+(defn prep [{:keys [compile-path checksum-deps] :as project} skip-auto-compile]
+ (when (and (not (or *skip-auto-compile* skip-auto-compile)) compile-path
+ (empty? (.list (file compile-path))))
(binding [*silently* true]
(compile project)))
- (when (or (empty? (find-jars project))
- (:checksum-deps project))
- (deps project)))
+ (when (or (empty? (find-deps-files project)) checksum-deps)
+ (deps project))
+ (when compile-path
+ (.mkdirs (file compile-path))))
-(defn- add-system-property [java key value]
- (.addSysproperty java (doto (Environment$Variable.)
- (.setKey (name key))
- (.setValue (name value)))))
+(defn eval-in-leiningen [project form-string]
+ ;; bootclasspath workaround: http://dev.clojure.org/jira/browse/CLJ-673
+ (require '[clojure walk repl])
+ (require '[clojure.java io shell browse])
+ (when (:debug project)
+ (System/setProperty "clojure.debug" "true"))
+ ;; need to at least pretend to return an exit code
+ (try (binding [*warn-on-reflection* (:warn-on-reflection project), *ns* *ns*]
+ (eval (read-string form-string)))
+ 0
+ (catch Exception e
+ (.printStackTrace e)
+ 1)))
+
+(defn- pump [reader out]
+ (let [buffer (make-array Character/TYPE 1000)]
+ (loop [len (.read reader buffer)]
+ (when-not (neg? len)
+ (.write out buffer 0 len)
+ (.flush out)
+ (Thread/sleep 100)
+ (recur (.read reader buffer))))))
+
+;; clojure.java.shell/sh doesn't let you stream out/err
+(defn sh [& cmd]
+ (let [proc (.exec (Runtime/getRuntime) (into-array cmd))]
+ (with-open [out (reader (.getInputStream proc))
+ err (reader (.getErrorStream proc))]
+ (let [pump-out (doto (Thread. #(pump out *out*)) .start)
+ pump-err (doto (Thread. #(pump err *err*)) .start)]
+ (.join pump-out)
+ (.join pump-err))
+ (.waitFor proc))))
+
+(defn eval-in-subprocess [project form-string]
+ (apply sh `(~(or (System/getenv "JAVA_CMD") "java")
+ "-cp" ~(get-classpath-string project)
+ ~@(get-jvm-args project)
+ "clojure.main" "-e" ~form-string)))
-;; TODO: split this function up
(defn eval-in-project
"Executes form in an isolated classloader with the classpath and compile path
set correctly for the project. If the form depends on any requires, put them
@@ -140,55 +192,24 @@
(when skip-auto-compile
(println "WARNING: eval-in-project's skip-auto-compile arg is deprecated."))
(prep project skip-auto-compile)
- (if (:eval-in-leiningen project)
- (do ;; bootclasspath workaround: http://dev.clojure.org/jira/browse/CLJ-673
- (require '[clojure walk repl])
- (require '[clojure.java io shell browse])
- (when (:debug project)
- (System/setProperty "clojure.debug" "true"))
- ;; need to at least pretend to return an exit code
- (try (binding [*warn-on-reflection* (:warn-on-reflection project)
- *ns* *ns*]
- (eval (read-string (get-readable-form nil project form init))))
- 0
- (catch Exception e
- (.printStackTrace e)
- 1)))
- (let [java (Java.)]
- (.setProject java lancet/ant-project)
- (add-system-property java :clojure.compile.path (:compile-path project))
- (add-system-property java (format "%s.version" (:name project))
- (:version project))
- (when (:debug project)
- (add-system-property java :clojure.debug true))
- (when (.exists (file (:native-path project)))
- (add-system-property java "java.library.path" (:native-path project)))
- ;; TODO: remove in 2.0?
- (when (and (paths/legacy-native-path project)
- (.exists (file (paths/legacy-native-path project))))
- (add-system-property java "java.library.path"
- (str (paths/legacy-native-path project))))
- (.setClasspath java (apply make-path (get-classpath project)))
- (.setFailonerror java true)
- (.setFork java true)
- (.setDir java (file (:root project)))
- (doseq [arg (get-jvm-args project)]
- (.setValue (.createJvmarg java) arg))
- (.setClassname java "clojure.main")
- ;; to allow plugins and other tasks to customize
- (when handler
- (println "WARNING: eval-in-project's handler argument is deprecated.")
- (handler java))
- (.setValue (.createArg java) "-e")
- (.setValue (.createArg java) (get-readable-form java project form init))
- (.executeJava java))))
+ (let [form-string (get-readable-form nil project form init)]
+ (if (:eval-in-leiningen project)
+ (eval-in-leiningen project form-string)
+ (eval-in-subprocess project form-string))))
+
+ ;; .class file cleanup
(defn- has-source-package?
- "Test if the class file's package exists as a directory in :source-path."
+ "Test if the class file's package exists as a directory in source-path."
[project f source-path]
- (and source-path (.isDirectory (file (.replace (.getParent f)
- (:compile-path project)
- source-path)))))
+ (and source-path
+ (let [[[parent] [_ _ proxy-mod-parent]]
+ (->> f, (iterate #(.getParentFile %)),
+ (take-while identity), rest,
+ (split-with #(not (re-find #"^proxy\$" (.getName %)))))]
+ (.isDirectory (file (.replace (.getPath (or proxy-mod-parent parent))
+ (:compile-path project)
+ source-path))))))
(defn- class-in-project? [project f]
(or (has-source-package? project f (:source-path project))
@@ -223,8 +244,10 @@
(blacklisted-class? project f))]
(.delete f))))
+ ;; actual task
+
(defn- status [code msg]
- (when-not *silently*
+ (when-not *silently* ; TODO: should silently only affect success?
(binding [*out* (if (zero? code) *out* *err*)]
(println msg)))
code)
@@ -238,7 +261,6 @@
Uses the namespaces specified under :aot in project.clj or those given
as command-line arguments."
([project]
- (.mkdir (file (:compile-path project)))
(when (:java-source-path project)
(javac project))
(if (seq (compilable-namespaces project))
View
69 src/leiningen/core.clj
@@ -7,7 +7,7 @@
(:import (java.io File)
(org.apache.maven.artifact.versioning DefaultArtifactVersion)))
-(def *interactive?* false)
+(def ^{:dynamic true} *interactive?* false)
(defmacro defdeprecated [old new]
`(let [new# ~(str (.getName (:ns (meta (resolve new)))) "/" (name new))
@@ -35,7 +35,9 @@ Warning: alpha; subject to change."
[]
(let [init-file (File. (paths/leiningen-home) "init.clj")]
(when (.exists init-file)
- (load-file (.getAbsolutePath init-file)))))
+ (try (load-file (.getAbsolutePath init-file))
+ (catch Exception e
+ (.printStackTrace e))))))
(defn user-settings
"Look up the settings map from init.clj or an empty map if it doesn't exist."
@@ -74,6 +76,7 @@ Warning: alpha; subject to change."
(:deps m#))
:dev-dependencies (or (:dev-dependencies m#)
(:dev-deps m#))
+ :checksum-deps (:checksum-deps m# true)
:compile-path (normalize-path#
(or (:compile-path m#) "classes"))
:source-path (normalize-path#
@@ -128,6 +131,14 @@ Warning: alpha; subject to change."
;; TODO: possibly separate releases/snapshots in 2.0.
"clojars" {:url "http://clojars.org/repo/"}})
+;; you can't remove or omit "central", you can only disable it;
+;; maven/maven-ant-tasks adds it implicitly, and will continue to
+;; report it in the list of checked repositories, even though it's
+;; not been consulted. The URL will hopefully be clear enough to users.
+(def disabled-central-repo {"central" {:url "http://disabled-central"
+ :snapshots false
+ :releases false}})
+
(defn- init-settings [id settings]
(cond (string? settings) {:url settings}
;; infer snapshots/release policy from repository id
@@ -136,12 +147,29 @@ Warning: alpha; subject to change."
:else settings))
(defn repositories-for
- "Return a map of repositories including or excluding defaults."
- [project]
- (merge (when-not (:omit-default-repositories project)
- default-repos)
- (into {} (for [[id settings] (:repositories project)]
- [id (init-settings id settings)]))))
+ "Returns an ordered map of repositories including or excluding defaults.
+
+ By default bases results on contents of :repositories. If another key
+ is specified via a :kind kwarg, that key will be used to query the
+ project. e.g. (repositories-for project :kind :deploy-repositories)
+ will return an ordered map of repositories intended solely for deployment
+ operations.
+
+ Note: transforming this map via assoc, merge, or similar removes the
+ order guarantee."
+ [project & {:keys [kind] :or {kind :repositories}}]
+ (let [project-repos (for [[id settings] (kind project)]
+ [id (init-settings id settings)])
+ user-deploy-repos (when (= kind :deploy-repositories)
+ (into [] (:deploy-repositories (user-settings))))
+ all-repos (concat
+ (into []
+ (if (:omit-default-repositories project)
+ disabled-central-repo
+ default-repos))
+ user-deploy-repos
+ project-repos)]
+ (apply array-map (mapcat identity all-repos))))
(defn exit
"Call System/exit. Defined as a function so that rebinding is possible."
@@ -159,6 +187,8 @@ Warning: alpha; subject to change."
;;; Task execution
+(def ^{:dynamic true} *current-task* nil)
+
(def aliases (atom {"--help" "help" "-h" "help" "-?" "help" "-v" "version"
"--version" "version" "überjar" "uberjar" "cp" "classpath"
"int" "interactive"}))
@@ -224,9 +254,10 @@ Warning: alpha; subject to change."
(defn apply-task [task-name project args not-found]
(let [task (resolve-task task-name not-found)]
(if-let [parameters (matching-arity? task-name project args)]
- (if (project-accepted? parameters)
- (apply task project args)
- (apply task args))
+ (binding [*current-task* task-name]
+ (if (project-accepted? parameters)
+ (apply task project args)
+ (apply task args)))
(let [args (arglists task-name)]
(if (and (not project) (project-needed? args))
(abort "Couldn't find project.clj, which is needed for" task-name)
@@ -270,14 +301,14 @@ Takes major, minor and incremental versions into account."
[project]
(when-not (version-greater-eq? (System/getenv "LEIN_VERSION")
(:min-lein-version project))
- (do (println (str "\n*** Warning: This project requires Leiningen version "
- (:min-lein-version project)
- " ***"
- "\n*** Using version " (System/getenv "LEIN_VERSION")
- " could cause problems. ***\n"
- "\n- Get the latest verison of Leiningen at\n"
- "- https://github.com/technomancy/leiningen\n"
- "- Or by executing \"lein upgrade\"\n\n")))))
+ (println (str "\n*** Warning: This project requires Leiningen version "
+ (:min-lein-version project)
+ " ***"
+ "\n*** Using version " (System/getenv "LEIN_VERSION")
+ " could cause problems. ***\n"
+ "\n- Get the latest verison of Leiningen at\n"
+ "- https://github.com/technomancy/leiningen\n"
+ "- Or by executing \"lein upgrade\"\n\n"))))
(defn -main
([task-name & args]
View
7 src/leiningen/deploy.clj
@@ -16,8 +16,10 @@
(.setArtifact (make-artifact (make-model project)))))
(defn- get-repository [project repository-name]
- (let [repositories (repositories-for project)
- repository (or (repositories repository-name)
+ (let [deploy-repositories (repositories-for project :kind :deploy-repositories)
+ repositories (repositories-for project)
+ repository (or (deploy-repositories repository-name)
+ (repositories repository-name)
{:url repository-name})]
(make-repository [repository-name repository])))
@@ -49,6 +51,7 @@ control:
(.setFile (file (jar project)))
(.addPom (doto (Pom.)
(.setMavenProject (make-maven-project project))
+ (.setProject lancet/ant-project)
(.setFile (file (pom project)))))
(.addRemoteRepository (get-repository project repository-name))
(.execute))
View
35 src/leiningen/deps.clj
@@ -1,7 +1,9 @@
(ns leiningen.deps
"Download all dependencies and put them in :library-path."
(:require [lancet.core :as lancet])
- (:use [leiningen.core :only [repositories-for user-settings no-dev?]]
+ (:use [leiningen.core :only [repositories-for user-settings
+ *current-task* no-dev?]]
+ [leiningen.clean :only [clean]]
[leiningen.util.maven :only [make-dependency]]
[leiningen.util.file :only [delete-file-recursively]]
[leiningen.util.paths :only [get-os get-arch]]
@@ -94,7 +96,7 @@
;; private methods, we'll call a public method that we know calls
;; getContainer, getSupportedProtocols.
(.getSupportedProtocols deps-task)
- (.setBasedir lancet/ant-project (:root project))
+ (.setBasedir lancet/ant-project (:root project ""))
(.setFilesetId deps-task "dependency.fileset")
(.setPathId deps-task (:name project))
(doseq [repo (make-repositories project)]
@@ -120,7 +122,8 @@
(defn fetch-deps? [project]
(let [deps-checksum-file (new-deps-checksum-file project)]
(and (has-dependencies? project)
- (or (empty? (.list (File. (:library-path project))))
+ (or (= "deps" *current-task*)
+ (empty? (.list (File. (:library-path project))))
(not (:checksum-deps project (:checksum-deps (user-settings))))
(not (.exists deps-checksum-file))
(not= (slurp deps-checksum-file) (deps-checksum project))))))
@@ -159,41 +162,41 @@
(.listFiles (file (:library-path project))))
;; TODO: memoize when not in tests
-(defn ^{:internal true} find-jars
- "Returns a seq of Files for all the jars in the project's library directory."
- [project]
- (filter #(.endsWith (.getName %) ".jar")
- (concat (if (:local-repo-classpath project)
+(defn ^{:internal true} find-deps-files [project]
+ (remove #{(file (:root project) "lib/dev")}
+ (concat (if (:local-repo-classpath project) ; TODO: default in 2.0
(find-local-repo-jars project)
(find-lib-jars project))
;; This must be hard-coded because it's used in
;; bin/lein and thus can't be changed in project.clj.
(.listFiles (file (:root project) "lib/dev")))))
-(def native-subdir (format "native/%s/%s/" (name (get-os)) (name (get-arch))))
+(defn- find-jars [project]
+ (filter #(.endsWith (.getName %) ".jar") (find-deps-files project)))
(defn extract-native-deps [project]
(doseq [jar (map #(JarFile. %) (find-jars project))
entry (enumeration-seq (.entries jar))
- :when (.startsWith (.getName entry) native-subdir)]
- (let [f (file (:native-path project)
- (subs (.getName entry) (count native-subdir)))]
+ :when (.startsWith (.getName entry) "native/")]
+ (let [f (file (:native-path project) (subs (.getName entry)
+ (count "native/")))]
(if (.isDirectory entry)
(.mkdirs f)
(copy (.getInputStream jar entry) f)))))
(defn deps
"Download :dependencies and put them in :library-path."
- [project & _]
- (when (seq _)
+ [project & [skip-dev]]
+ (when skip-dev
(println "WARNING: passing an argument to deps is deprecated."))
(when (fetch-deps? project)
(when-not (or (:disable-deps-clean project)
(:disable-implicit-clean project))
(delete-file-recursively (:library-path project) :silently)
- (delete-file-recursively (File. (:root project) "native") :silently))
+ (delete-file-recursively (:native-path project) :silently)
+ (clean project))
(let [fileset (do-deps project :dependencies)]
- (when-not (no-dev?)
+ (when-not (or skip-dev (no-dev?))
(do-deps project :dev-dependencies))
(extract-native-deps project)
(when (:checksum-deps project)
View
12 src/leiningen/install.clj
@@ -46,17 +46,21 @@ in your local repository. With two arguments, (group/name and version)
downloads and installs a project from a remote repository. Places
shell wrappers in ~/.lein/bin when provided."
([project]
- (let [jarfile (file (jar project))
+ (let [jarfile (jar project)
model (make-model project)
artifact (make-artifact model)
installer (.lookup container ArtifactInstaller/ROLE)
local-repo (make-local-repo)]
;; for packaging other than "pom" there should be "pom.xml"
;; generated and installed in local repo
- (if (not= "pom" (.getPackaging model))
+ (when (not= "pom" (.getPackaging model))
(add-metadata artifact (file (pom project))))
- (install-shell-wrappers (JarFile. jarfile))
- (.install installer jarfile artifact local-repo)))
+ (if (number? jarfile)
+ ;; if we failed to create the jar, return the status code for exit
+ jarfile
+ (do (install-shell-wrappers (JarFile. jarfile))
+ (.install installer (file jarfile) artifact local-repo)
+ 0))))
([project-name version]
(let [[name group] ((juxt name namespace) (symbol project-name))
_ (standalone-download name (or group name) version)
View
28 src/leiningen/interactive.clj
@@ -1,6 +1,7 @@
(ns leiningen.interactive
"Enter interactive task shell."
- (:require [clojure.string :as string])
+ (:require [clojure.string :as string]
+ [clojure.java.io :as io])
(:use [leiningen.core :only [apply-task exit *interactive?*]]
[leiningen.test :only [*exit-after-tests*]]
[leiningen.repl :only [repl-server repl-socket-on
@@ -14,24 +15,22 @@
(defn not-found [& _]
(println "That's not a task. Use help to list all tasks."))
-(defn- eval-client-loop [reader writer buffer socket]
- (let [len (.read reader buffer)
- output (String. buffer)]
+(defn- eval-client-loop [reader buffer socket]
+ (let [len (.read reader buffer)]
(when-not (neg? len)
(.write *out* buffer 0 len)
- (flush)
+ (.flush *out*)
(when-not (.isClosed socket)
(Thread/sleep 100)
- (recur reader writer buffer socket)))))
+ (recur reader buffer socket)))))
(defn eval-in-repl [connect project form & [_ _ init]]
(let [[reader writer socket] (connect)]
(.write writer (str "(do " (pr-str init)
(pr-str form) "\n" '
(.close *in*) ")\n"))
(.flush writer)
- (try (eval-client-loop reader writer
- (make-array Character/TYPE 1000) socket)
+ (try (eval-client-loop reader (make-array Character/TYPE 1000) socket)
0
(catch Exception e
(.printStackTrace e) 1)
@@ -59,16 +58,19 @@
(recur (.readLine *in*))))))
(defn interactive
- "Enter an interactive task shell."
+ "Enter an interactive task shell. Aliased to \"int\"."
[project]
+ (.delete (io/file "/tmp/bugger-all"))
(let [[port host] (repl-socket-on project)]
(println welcome)
(future
(binding [*interactive?* true]
- (eval-in-project project `(do ~(repl-server project host port
- :prompt '(constantly ""))
- ;; can't stop return value from printing
- (symbol "")))))
+ (eval-in-project project (repl-server project host port
+ :prompt '(fn [])
+ :caught '(fn [t]
+ (println (.getMessage t))
+ (.printStackTrace t)
+ (.close *in*))))))
(let [connect #(poll-repl-connection port 0 vector)]
(binding [eval-in-project (partial eval-in-repl connect)
*exit-after-tests* false
View
22 src/leiningen/jar.clj
@@ -103,7 +103,8 @@
(zipmap (map str (keys attrs)) (vals attrs))))
(defn skip-file? [file relative-path patterns]
- (or (.isDirectory file)
+ (or (not (.exists file))
+ (.isDirectory file)
(re-find #"^\.?#" (.getName file))
(re-find #"~$" (.getName file))
(some #(re-find % relative-path) patterns)))
@@ -127,8 +128,9 @@
(copy child jar-os))))))
(defmethod copy-to-jar :bytes [project jar-os spec]
- (.putNextEntry jar-os (JarEntry. (:path spec)))
- (copy (ByteArrayInputStream. (:bytes spec)) jar-os))
+ (when-not (some #(re-find % (:path spec)) (:jar-exclusions project))
+ (.putNextEntry jar-os (JarEntry. (:path spec)))
+ (copy (ByteArrayInputStream. (:bytes spec)) jar-os)))
(defn write-jar [project out-filename filespecs]
(let [manifest (make-manifest project)]
@@ -171,6 +173,9 @@
(when (and (:resources-path project)
(.exists (file (:resources-path project))))
[{:type :path :path (:resources-path project)}])
+ (when (and (:java-source-path project)
+ (not (:omit-source project)))
+ [{:type :path :path (:java-source-path project)}])
(when-not (:omit-source project)
[{:type :path :path (:source-path project)}])
(shell-wrapper-filespecs project deps-fileset)))
@@ -198,11 +203,12 @@ function in that namespace will be used as the main-class for executable jar."
([project jar-name]
(when jar-name
(println "WARNING: Using the jar task with an argument is deprecated."))
- (binding [compile/*silently* true]
- (when (zero? (compile/compile project))
- (let [jar-path (get-jar-filename project (get-default-jar-name project))
- deps-fileset (deps project)]
+ (let [deps-fileset (deps (assoc project :checksum-deps false))
+ status (compile/compile project)]
+ (if (zero? status)
+ (let [jar-path (get-jar-filename project (get-default-jar-name project))]
(write-jar project jar-path (filespecs project deps-fileset))
(println "Created" jar-path)
- jar-path))))
+ jar-path)
+ status)))
([project] (jar project nil)))
View
4 src/leiningen/javac.clj
@@ -5,7 +5,9 @@
(:require [lancet.core :as lancet])
(:import (java.io File)))
-(def ^{:doc "Default options for the java compiler."} *default-javac-options*
+(def ^{:doc "Default options for the java compiler."
+ :dynamic true}
+ *default-javac-options*
{:debug "false" :fork "true"
:includejavaruntime "yes"
:includeantruntime "false"
View
15 src/leiningen/new.clj
@@ -1,6 +1,6 @@
(ns leiningen.new
"Create a new project skeleton."
- (:use [leiningen.core :only [abort user-settings]]
+ (:use [leiningen.core :only [abort]]
[leiningen.util.paths :only [ns->path]]
[clojure.java.io :only [file]]
[clojure.string :only [join]])
@@ -16,10 +16,9 @@
(format-map settings)))))
(defn write-project [project-dir project-name]
- (let [default-settings {:dependencies [['org.clojure/clojure "1.2.1"]]}
+ (let [default-settings {:dependencies [['org.clojure/clojure "1.3.0"]]}
settings (merge-with #(if %2 %2 %1)
- default-settings
- (user-settings))]
+ default-settings)]
(.mkdirs (file project-dir))
(spit (file project-dir "project.clj")
(str "(defproject " project-name " \"1.0.0-SNAPSHOT\"\n"
@@ -77,10 +76,12 @@
test-ns (str prefix ".test.core")
project-clj (ns->path project-ns)]
(spit (file project-dir ".gitignore")
- (apply str (interleave ["pom.xml" "*jar" "/lib/" "/classes/"
- ".lein-failures" ".lein-deps-sum"]
+ (apply str (interleave ["/pom.xml" "*jar" "/lib" "/classes"
+ "/native" "/.lein-failures" "/checkouts"
+ "/.lein-deps-sum"]
(repeat "\n"))))
(write-implementation project-dir project-clj project-ns)
(write-test project-dir test-ns project-ns)
(write-readme project-dir artifact-id)
- (println "Created new project in:" project-dir)))))
+ (println "Created new project in:" project-dir)
+ (println "Look over project.clj and start coding in" project-clj)))))
View
41 src/leiningen/plugin.clj
@@ -21,14 +21,34 @@
(defn extract-name-and-group [project-name]
((juxt name namespace) (symbol project-name)))
+(defn uninstall
+ "Delete the plugin jarfile
+Syntax: lein plugin uninstall [GROUP/]ARTIFACT-ID VERSION"
+ [project-name version]
+ (let [[name group] (extract-name-and-group project-name)
+ jarfile (file plugins-path
+ (plugin-standalone-filename group name version))]
+ (if (.exists jarfile)
+ (if (.delete jarfile)
+ (println (format "Uninstalled %s %s." project-name version))
+ (abort (format "Failed to delete \"%s\"." (.getAbsolutePath jarfile))))
+ (abort (format "Plugin \"%s %s\" doesn't appear to be installed."
+ project-name version)))))
+
+(defn- uninstall-old [project-name]
+ (doseq [plugin (.list plugins-path)
+ :let [pat (re-pattern (format "^\\Q%s\\E-.*\\.jar$" project-name))]
+ :when (re-find pat plugin)]
+ (.delete (file plugins-path plugin))))
+
;; TODO: extract shared behavior between this and the install task
(defn install
- "Download, package, and install plugin jarfile into
- ~/.lein/plugins
+ "Download, package, and install plugin jarfile into ~/.lein/plugins
Syntax: lein plugin install [GROUP/]ARTIFACT-ID VERSION
You can use the same syntax here as when listing Leiningen
dependencies."
[project-name version]
+ (uninstall-old project-name)
(leiningen.install/install project-name version)
(.mkdirs plugins-path)
(let [[name group] (extract-name-and-group project-name)
@@ -38,7 +58,8 @@ Syntax: lein plugin install [GROUP/]ARTIFACT-ID VERSION
_ (extract-jar (file jarfile) temp-project)
project (read-project (str (file temp-project "project.clj")))
standalone-filename (plugin-standalone-filename group name version)]
- (deps (dissoc project :dev-dependencies :native-dependencies))
+ (deps (dissoc project :dev-dependencies :native-dependencies
+ :eval-in-leiningen))
(with-open [out (-> (file plugins-path standalone-filename)
(FileOutputStream.)
(ZipOutputStream.))]
@@ -49,20 +70,6 @@ Syntax: lein plugin install [GROUP/]ARTIFACT-ID VERSION
(delete-file-recursively temp-project)
(println "Created" standalone-filename)))
-(defn uninstall
- "Delete the plugin jarfile
-Syntax: lein plugin uninstall [GROUP/]ARTIFACT-ID VERSION"
- [project-name version]
- (let [[name group] (extract-name-and-group project-name)
- jarfile (file plugins-path
- (plugin-standalone-filename group name version))]
- (if (.exists jarfile)
- (if (.delete jarfile)
- (println (format "Uninstalled %s %s." project-name version))
- (abort (format "Failed to delete \"%s\"." (.getAbsolutePath jarfile))))
- (abort (format "Plugin \"%s %s\" doesn't appear to be installed."
- project-name version)))))
-
(defn ^{:doc "Manage user-level plugins."
:help-arglists '([subtask project-name version])
:subtasks [#'install #'uninstall]}
View
19 src/leiningen/repl.clj
@@ -3,14 +3,14 @@
(:require [clojure.main])
(:use [leiningen.core :only [exit user-settings *interactive?*]]
[leiningen.compile :only [eval-in-project]]
- [leiningen.deps :only [find-jars deps]]
+ [leiningen.deps :only [find-deps-files deps]]
[leiningen.trampoline :only [*trampoline?*]]
[clojure.java.io :only [copy]])
(:import (java.net Socket InetAddress ServerSocket SocketException)
(java.io OutputStreamWriter InputStreamReader File PrintWriter)
(clojure.lang LineNumberingPushbackReader)))
-(def *retry-limit* 200)
+(def retry-limit 200)
(defn repl-options [project options]
(let [options (apply hash-map options)
@@ -55,12 +55,13 @@
(let [server# (ServerSocket. ~port 0 (InetAddress/getByName ~host))
acc# (fn [s#]
(let [ins# (.getInputStream s#)
- outs# (.getOutputStream s#)]
+ outs# (.getOutputStream s#)
+ out-writer# (OutputStreamWriter. outs#)]
(doto (Thread.
#(binding [*in* (-> ins# InputStreamReader.
LineNumberingPushbackReader.)
- *out* (OutputStreamWriter. outs#)
- *err* *err*
+ *out* out-writer#
+ *err* (PrintWriter. out-writer#)
*warn-on-reflection*
~(:warn-on-reflection project)]
(clojure.main/repl
@@ -105,7 +106,7 @@
(defn poll-repl-connection
([port retries handler]
- (when (> retries *retry-limit*)
+ (when (> retries retry-limit)
(throw (Exception. "Couldn't connect")))
(Thread/sleep 100)
(let [val (try (connect-to-server (Socket. "localhost" port) handler)
@@ -132,17 +133,17 @@ A socket-repl will also be launched in the background on a socket based on the
directory will start a standalone repl session."
([] (repl nil))
([project]
- (when (and project (or (empty? (find-jars project))
+ (when (and project (or (empty? (find-deps-files project))
(:checksum-deps project)))
(deps project))
(let [[port host] (repl-socket-on project)
server-form (apply repl-server project host port
(concat (:repl-options project)
(:repl-options (user-settings))))
;; TODO: make this less awkward when we can break poll-repl-connection
- retries (- *retry-limit* (or (:repl-retry-limit project)
+ retries (- retry-limit (or (:repl-retry-limit project)
((user-settings) :repl-retry-limit)
- *retry-limit*))]
+ retry-limit))]
(if *trampoline?*
(eval-in-project project server-form)
(do (future (if (empty? project)
View
31 src/leiningen/run.clj
@@ -1,23 +1,30 @@
(ns leiningen.run
"Run a -main function with optional command-line arguments."
(:use [leiningen.compile :only [eval-in-project]]
- [leiningen.core :only [abort]]))
+ [leiningen.core :only [abort]])
+ (:import (java.io FileNotFoundException)
+ (clojure.lang Reflector)))
-(defn- get-ns-and-fn [given]
- (if (= 'clojure.main given) ; special-case this oddity
- ['clojure.main 'main]
- (let [[given-ns given-sym] ((juxt namespace name) given)]
- (map symbol (if given-ns
- [given-ns given-sym]
- [given-sym "-main"])))))
+(defn- normalize-main [given]
+ (if (namespace (symbol given))
+ (symbol given)
+ (symbol (name given) "-main")))
+
+(defn- run-form [given args]
+ `(let [v# (resolve '~(normalize-main given))]
+ (if (ifn? v#)
+ (v# ~@args)
+ (Reflector/invokeStaticMethod
+ ~(name given) "main" (into-array [(into-array String '~args)])))))
(defn- run-main
"Loads the project namespaces as well as all its dependencies and then calls
ns/f, passing it the args."
- ([project given-main & args]
- (let [[main-ns main-fn] (get-ns-and-fn (symbol given-main))]
- (eval-in-project project `((ns-resolve '~main-ns '~main-fn) ~@args)
- nil nil `(require '~main-ns)))))
+ [project given & args]
+ (eval-in-project project (run-form given args)
+ nil nil `(try (require '~(symbol (namespace
+ (normalize-main given))))
+ (catch FileNotFoundException _#))))
(defn ^{:help-arglists '([])} run
"Run the project's -main function.
View
22 src/leiningen/search.clj
@@ -27,7 +27,7 @@
(defn- download-index [[id {url :url}]]
(with-open [stream (.openStream (remote-index-url url))]
- (println "Downloading index from" id "-" url)
+ (println "Downloading index from" id "-" url "... this may take a while.")
(let [tmp (java.io.File/createTempFile "lein" "index")]
(try (io/copy stream tmp)
(unzip tmp (index-location url))
@@ -45,7 +45,7 @@
;;; Searching
-(def ^{:private true} page-size (:search-page-size (user-settings) 10))
+(def ^{:private true} page-size (:search-page-size (user-settings) 25))
(defn search-repository [[id {:keys [url]} :as repo] query page]
(if (ensure-fresh-index repo)
@@ -69,18 +69,24 @@
(defn- print-results [[id] results page]
(when (seq results)
(println " == Results from" id "-" "Showing page" page "/"
- ;; TODO: divide by page size?
- (:_total-hits (meta results) page-size) "total")
+ (-> results meta :_total-hits (/ page-size) Math/ceil int) "total")
(doseq [result (map parse-result results)]
(apply println result))
(prn)))
(defn ^{:help-arglists '([query] [query page])} search
- "Search remote repositories.
+ "Search remote maven repositories for matching jars.
-The first run will download a set of indices, which will take a
-while. Pass in --update as the query to force a fresh download of all
-indices. Also accepts a second parameter for fetching successive pages."
+The first run will download a set of indices, which will take a while.
+Pass in --update as the query to force a fresh download of all
+indices.
+
+The query is evaluated as a lucene search. You can search for simple
+string matches or do more advanced queries such as this
+'lein search \"clojure AND http AND NOT g:org.clojars*\"'
+
+Also accepts a second parameter for fetching successive
+pages."
;; support running outside project
([query] (search {} query))
([project-or-query query-or-page]
View
4 src/leiningen/test.clj
@@ -8,7 +8,7 @@
(:import (java.io File)))
;; TODO: switch to using *interactive* flag in 2.0.
-(def *exit-after-tests* true)
+(def ^{:dynamic true} *exit-after-tests* true)
(defn- form-for-hook-selectors [selectors]
`(when (seq ~selectors)
@@ -45,7 +45,7 @@ each namespace and print an overall summary."
(java.io.OutputStreamWriter.))]
(.write w# (pr-str summary#)))
(when (or ~*exit-after-tests* (not ~*interactive?*))
- (System/exit 0))))))
+ (System/exit (+ (:error summary#) (:fail summary#))))))))
(defn- read-args [args project]
(let [args (map read-string args)
View
55 src/leiningen/trampoline.clj
@@ -1,45 +1,24 @@
(ns leiningen.trampoline
(:refer-clojure :exclude [trampoline])
(:use [leiningen.core :only [apply-task task-not-found abort]]
- [leiningen.compile :only [get-readable-form prep eval-in-project]]
+ [leiningen.compile :only [sh]]
[leiningen.classpath :only [get-classpath-string]])
(:require [clojure.string :as string]
[clojure.java.io :as io]
+ [clojure.java.shell :as shell]
[leiningen.util.paths :as paths]))
-(def *trampoline?* false)
-
-(defn get-jvm-opts [project]
- (let [legacy-native (paths/legacy-native-path project)]
- (filter identity [(if (not (empty? (System/getenv "JVM_OPTS")))
- (System/getenv "JVM_OPTS"))
- (if (:debug project)
- "-Dclojure.debug=true")
- (if (.exists (io/file (:native-path project)))
- (str "-Djava.library.path=" (:native-path project))
- (if (.exists (io/file legacy-native))
- (str "-Djava.library.path=" legacy-native)))])))
+(def ^{:dynamic true} *trampoline?* false)
(defn win-batch? []
(.endsWith (System/getProperty "leiningen.trampoline-file") ".bat"))
-(defn escape [form-string]
- (if (win-batch?)
- form-string
- (format "\"%s\"" (.replaceAll form-string "\"" "\\\\\""))))
-
-(defn quote-path [string]
- (format "\"%s\"" (if (win-batch?) string (.replace string "\\" "\\\\"))))
-
-(defn command-string [project java-cmd jvm-opts [form init]]
- (string/join " " [(quote-path java-cmd)
- "-cp" (quote-path (get-classpath-string project))
- (string/join " " (map quote-path jvm-opts))
- "clojure.main" "-e"
- (escape (get-readable-form (win-batch?) project form init))]))
-
(defn write-trampoline [command]
- (spit (System/getProperty "leiningen.trampoline-file") command))
+ (spit (System/getProperty "leiningen.trampoline-file")
+ (string/join " " (if (win-batch?)
+ command
+ (conj (vec (butlast command))
+ (with-out-str (prn (last command))))))))
(defn trampoline