Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 14e3059
Showing
4 changed files
with
277 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pom.xml | ||
*jar | ||
lib | ||
classes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# lein-oneoff | ||
|
||
Dealing with dependencies and the classpath can be a | ||
pain. [Leiningen](http://github.com/technomancy/leiningen) takes most | ||
of the pain away, but creating a new leiningen project for a simple | ||
one-off script may sometimes feel like overkill. This is where | ||
[lein-oneoff](http://github.com/mtyaka/lein-oneoff) comes in. | ||
|
||
With the help of lein-oneoff you can open a file, declare | ||
dependencies at the top and write the rest of the code as | ||
usually. lein-oneoff will let you run the file, open a repl or start a swank | ||
server while taking care of fetching dependencies and constructing the | ||
classpath automatically. | ||
|
||
## Usage | ||
|
||
lein-oneoff scripts usually consist of a single file. Dependencies | ||
should be stated at the top using the `defdeps` form. Here's an example: | ||
|
||
(defdeps | ||
[[org.clojure/clojure "1.2.0"] | ||
[compojure "0.5.2"] | ||
[ring/ring-jetty-adapter "0.3.3"]]) | ||
|
||
(ns example | ||
(:use [compojure.core] | ||
[ring.adapter.jetty :only [run-jetty]])) | ||
|
||
(defroutes routes | ||
(GET "/" [] "Hello world!")) | ||
|
||
(def server | ||
(run-jetty routes {:port 8080 :join? false})) | ||
|
||
Save this file as `example.clj`, then run it with: | ||
|
||
$ lein oneoff example.clj | ||
|
||
This command will check the specified dependencies and install them | ||
into the local maven repository (`~/.m2/repository`) unless already | ||
installed, and then run `example.clj` with the necessary dependencies | ||
in the classpath. Note that the dependencies are referenced directly | ||
from the local maven repository. | ||
|
||
### The defdeps form | ||
|
||
The `defdeps` form must be the first form in the file. It has the following | ||
signature: | ||
|
||
(defdeps dependencies additional-entries?) | ||
|
||
where dependencies should be specified as a vector using the same | ||
syntax as inside regular leiningen `defproject` form under the | ||
`:dependencies` key. The second argument is an optional map of | ||
additional standard `defproject` entries. Please note that not | ||
all of the available leinigen options make sense for a one-off script | ||
and might not work correctly. | ||
|
||
One of the entries that can be useful is the `:repositories` entry. Here's | ||
an example: | ||
|
||
(defdeps | ||
[[org.clojure/clojure "1.3.0-alpha3"] | ||
[org.apache.pivot/pivot-web "1.5.2"]] | ||
{:repositories | ||
{"apache" "https://repository.apache.org/content/repositories/releases/"}}) | ||
|
||
The `defdeps` form may be omitted in which case the only assumed | ||
dependency is `org.clojure/clojure` of the same version as your leiningen | ||
installation is using. | ||
|
||
### repl | ||
|
||
To start a repl in the context of a one-off script, use the `--repl` | ||
command (or its shorter equivalent, `-r`): | ||
|
||
$ lein oneoff --repl example.clj | ||
$ lein oneoff -r example.clj | ||
|
||
### swank | ||
|
||
A swank server can be started with the `--swank` (or `-s`) | ||
command: | ||
|
||
$ lein oneoff --swank example.clj | ||
$ lein oneoff -s example.clj | ||
|
||
Please note that for the swank command to work, you'll need to have | ||
`swank-clojure` installed as a global leiningen plugin. At the moment, | ||
only `swank-clojure 1.3.0-SNAPSHOT` is supported. | ||
|
||
### classpath | ||
|
||
lein-oneoff offers an equivalent to leiningen's built-in `classpath` | ||
task which prints the project's classpath for one-off scripts: | ||
|
||
$ lein oneoff --classpath example.clj | ||
$ lein oneoff -c example.clj | ||
|
||
## Installation | ||
|
||
This plugin should be installed as a user-level leiningen plugin. Using | ||
leiningen 1.3.1, the easiest way to get going is to drop the | ||
lein-oneoff jar into the `$HOME/.lein/plugins` folder. Leiningen 1.4.0 | ||
will come with a special task for installing user-level plugins. | ||
|
||
lein-oneoff has been tested with leiningen 1.3.1 and 1.4.0-RC1. | ||
|
||
### Windows notes | ||
|
||
Windows lein.bat script that comes with leiningen 1.3.1 doesn't | ||
support user-level leiningen plugins. This was fixed on the master | ||
branch, so if you're using 1.3.1 on windows you might want to replace your | ||
lein.bat file with [the latest | ||
one](http://github.com/technomancy/leiningen/raw/master/bin/lein.bat) | ||
and then change the version in the second line to 1.3.1. | ||
|
||
## License | ||
|
||
Copyright (C) 2010 Matjaz Gregoric | ||
|
||
Distributed under the Eclipse Public License, the same as Clojure. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
(defproject lein-oneoff "0.0.1" | ||
:description "Dependency management for one-off scripts.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
(ns leiningen.oneoff | ||
(:use [robert.hooke :only [add-hook]] | ||
[leiningen.core :only [abort]]) | ||
(:require | ||
[lancet] | ||
[clojure.main] | ||
[leiningen compile classpath repl deps]) | ||
(:import java.io.File)) | ||
|
||
(try | ||
(require 'leiningen.swank) | ||
(catch java.io.FileNotFoundException e)) | ||
|
||
(def lein-swank-ns (find-ns 'leiningen.swank)) | ||
|
||
(def swank-form-var | ||
(when lein-swank-ns (ns-resolve lein-swank-ns 'swank-form))) | ||
|
||
(def default-deps | ||
`[[org.clojure/clojure ~(clojure-version)]]) | ||
|
||
(def defdeps-defmacro-form | ||
`(defmacro ~'defdeps [& args#])) | ||
|
||
(defn deps-classpath | ||
"Resolves and installs dependencies to the local maven repository. | ||
Returns a sequence of paths referencing jars in the repository." | ||
[project] | ||
(let [deps-task (leiningen.deps/make-deps-task project :dependencies) | ||
_ (.execute deps-task) | ||
fileset (.getReference lancet/ant-project | ||
(.getFilesetId deps-task)) | ||
dir-scanner (.getDirectoryScanner fileset lancet/ant-project) | ||
base-dir (.getBasedir dir-scanner)] | ||
(for [fpath (.getIncludedFiles dir-scanner)] | ||
(.getCanonicalPath (File. base-dir fpath))))) | ||
|
||
(defn get-oneoff-classpath | ||
"Returns a sequence of paths that constitute the full classpath | ||
for a one-off project." | ||
[project] | ||
(concat [(:root project)] | ||
(leiningen.classpath/user-plugins) | ||
(deps-classpath project))) | ||
|
||
(defn oneoff-deps-hook [deps project] | ||
(when-not (:oneoff project) (deps project))) | ||
|
||
(defn oneoff-get-classpath-hook [get-classpath project] | ||
(if (:oneoff project) | ||
(get-oneoff-classpath project) | ||
(get-classpath project))) | ||
|
||
(defn oneoff-eval-in-project-hook | ||
[eval-in-project project form & [handler skip-auto-compile init]] | ||
(let [skip-auto-compile (or (:oneoff project) skip-auto-compile)] | ||
(eval-in-project project form handler skip-auto-compile init))) | ||
|
||
(defn oneoff-repl-server-hook [repl-server project host port] | ||
(let [server-form (repl-server project host port)] | ||
(if (:oneoff project) | ||
`(do ~defdeps-defmacro-form ~server-form) | ||
server-form))) | ||
|
||
(defn oneoff-swank-form-hook [swank-form project port host opts] | ||
(let [server-form (swank-form project port host opts)] | ||
(if (:oneoff project) | ||
`(do ~defdeps-defmacro-form ~server-form) | ||
server-form))) | ||
|
||
(add-hook #'leiningen.deps/deps oneoff-deps-hook) | ||
(add-hook #'leiningen.compile/eval-in-project oneoff-eval-in-project-hook) | ||
(add-hook #'leiningen.classpath/get-classpath oneoff-get-classpath-hook) | ||
(add-hook #'leiningen.repl/repl-server oneoff-repl-server-hook) | ||
|
||
(when swank-form-var | ||
(add-hook swank-form-var oneoff-swank-form-hook)) | ||
|
||
(defn parse-defdeps [script] | ||
(let [contents (slurp script) | ||
forms (load-string (str "(quote [" contents "])")) | ||
form (first forms)] | ||
(if (= (first form) 'defdeps) | ||
[(nth form 1) (nth form 2 {})] | ||
[default-deps {}]))) | ||
|
||
(defn oneoff-project [script] | ||
(let [dir (System/getProperty "user.dir") | ||
[deps opts] (parse-defdeps script)] | ||
(merge | ||
{:oneoff true | ||
:name "A oneoff project" | ||
:version "1.0.0" | ||
:dependencies deps | ||
:root dir | ||
:compile-path (str dir "/classes") | ||
:library-path (str dir "/lib")} | ||
opts))) | ||
|
||
(defn print-usage [] | ||
(abort "Usage: lein oneoff <command> <file> | ||
<command> can be one of: --exec, --repl, --classpath, --swank. | ||
Short forms (-e, -r, -c, -s) may be used instead. | ||
If <command> is omitted, --exec is assumed.")) | ||
|
||
(defn execute-script [script] | ||
(let [project (oneoff-project script) | ||
form `(do | ||
~defdeps-defmacro-form | ||
(clojure.main/load-script ~script))] | ||
(leiningen.compile/eval-in-project project form))) | ||
|
||
(defn start-repl-server [script] | ||
(leiningen.repl/repl (oneoff-project script))) | ||
|
||
(defn start-swank-server [script] | ||
(if lein-swank-ns | ||
(if swank-form-var | ||
(let [swank-fn (ns-resolve lein-swank-ns 'swank)] | ||
(swank-fn (oneoff-project script))) | ||
(abort "The oneoff swank task only works with | ||
swank-clojure 1.3.0-SNAPSHOT or newer.")) | ||
(abort "You'll need to install swank-clojure as a user plugin | ||
for this task to work."))) | ||
|
||
(defn print-classpath [script] | ||
(leiningen.classpath/classpath (oneoff-project script))) | ||
|
||
(defn oneoff | ||
"Handles dependencies and execution of one-off scripts when creating a | ||
proper leiningen project feels like overkill. | ||
Syntax: lein oneoff <command> <file> | ||
<command> can be one of: --exec, --repl, --classpath, --swank. | ||
Short forms (-e, -r, -c, -s) may be used instead. | ||
If <command> is omitted, --exec is assumed. | ||
See http://github.com/mtyaka/lein-oneoff for more information." | ||
([cmd script] | ||
(case cmd | ||
("--exec" "-e") (execute-script script) | ||
("--repl" "-r") (start-repl-server script) | ||
("--classpath" "-c") (print-classpath script) | ||
("--swank" "-s") (start-swank-server script) | ||
(print-usage))) | ||
([script] | ||
(oneoff "--exec" script)) | ||
([] | ||
(print-usage))) |