It's configured using environment variables (one required and several
optional). It sets up the CLASSPATH for the Clojure instance it
launches based on the contents of a directory. This is a mechanism
similar to Java's java.ext.dirs facility but implemented without using
java.ext.dirs. I've tested this on Mac OS X Leopard and Ubuntu Intrepid.
Here's a description of the environment variables it uses:
# Environment variables:
#
# Required:
#
# CLOJURE_EXT The path to a directory containing (either directly or
as
# symbolic links) jar files and/or directories whose paths
# should be included in CLASSPATH. These paths will be
# prepended to any prior definition of the CLASSPATH
# environment variable.
#
# Optional:
#
# CLOJURE_JAVA The command to launch a JVM instance for Clojure
# default: java
# example: /usr/local/bin/java6
#
# CLOJURE_OPTS Java options for this JVM instance
# default:
# example:"-Xms32M -Xmx128M -server"
#
# CLOJURE_MAIN The Java class to launch
# default: clojure.main
# example: clojure.contrib.repl_ln
clj-env-dir can be used directly to launch Clojure or as a building
block for creating launch scripts for a variety of purposes.
Here are two examples of using it as a building block: (these also use
CLOJURE_CONTRIB whose value should be the path to an svn download
directory for clojure-contrib)
"clj" (stock clojure.main call, can launch a repl, script, or just
eval based on arguments to clj)
#!/bin/bash
export CLOJURE_MAIN=clojure.main
CLJ=$CLOJURE_CONTRIB/launchers/bash/clj-env-dir
OPTS=
exec $CLJ $OPTS "$@"
"cljr" (repl using clojure.contrib.repl_ln)
#!/bin/bash
export CLOJURE_MAIN=clojure.contrib.repl_ln
CLJ=$CLOJURE_CONTRIB/launchers/bash/clj-env-dir
OPTS="--init @repl_init.clj --repl"
exec $CLJ $OPTS "$@"
--Steve
I had a launch script (which I've now lost due to my own clumsiness)
that defaulted to a repl if given no file options, and always loaded a
.clojurerc.clj file before starting a repl (whether it was by default
or specifically asked via -r). This allowed me to load repl-utils and
get *print-length* set up before getting a prompt. But if a file was
named with now -r, it was run with no repl. It used appropriate
combinations of clojure.lang.Repl or clojure.lang.Script and file
paths to make this happen.
As far as I can tell this is impossible with clojure.main, which
appears to only allow loading a file *or* starting a repl. Am I
missing a method to support this, or should I go back to using
Script/Repl?
My script also accepted a -cp argument to augment any automatic or
default classpath it set up. I found this useful when tracking down
gen-class issues, but I never had this nice symlink-dir setup, which
might very well be better.
I apologize for not speaking up earlier in clojure.main's development,
when such issues probably could have been addressed more easily.
--Chouser
> I had a launch script (which I've now lost due to my own clumsiness)
> that defaulted to a repl if given no file options, and always loaded a
> .clojurerc.clj file before starting a repl (whether it was by default
> or specifically asked via -r). This allowed me to load repl-utils and
> get *print-length* set up before getting a prompt. But if a file was
> named with now -r, it was run with no repl. It used appropriate
> combinations of clojure.lang.Repl or clojure.lang.Script and file
> paths to make this happen.
>
> As far as I can tell this is impossible with clojure.main, which
> appears to only allow loading a file *or* starting a repl. Am I
> missing a method to support this, or should I go back to using
> Script/Repl?
If I understand correctly what you are looking for, it exists. Here
is my standard command line for starting Clojure:
java -cp $HOME/.clojure/clojure.jar:$HOME/.clojure/clojure-
contrib.jar clojure.main -i $HOME/.clojure/repl-init.clj -r
This first executes repl-init.clj (from where I load repl-utils, set
*print-length* etc.) and then starts the repl.
Konrad.
1) If I run "clj", it starts a REPL.
2) If I run "clj file-path", it runs that file as a Clojure script.
3) Some way to modify the classpath used by the script without
modifying the script.
--
R. Mark Volkmann
Object Computing, Inc.
You're absolutely right, that works just fine. In fact, it's
essentially what I already have.
But it wasn't working for me, because in my startup .clj I had (left
over from my old script):
(when (= (System/getProperty "repl") "yes")
(set! *print-length* 103)
(use 'clojure.contrib.repl-utils))
Maybe I should always start a repl. Why did I think I sometimes
wanted no repl? :-)
Anyway, thanks for the example.
--Chouser
I had a launch script (which I've now lost due to my own clumsiness)
that defaulted to a repl if given no file options, and always loaded a
.clojurerc.clj file before starting a repl (whether it was by default
or specifically asked via -r). This allowed me to load repl-utils and
get *print-length* set up before getting a prompt. But if a file was
named with [no] -r, it was run with no repl. It used appropriate
combinations of clojure.lang.Repl or clojure.lang.Script and file
paths to make this happen.
As far as I can tell this is impossible with clojure.main, which
appears to only allow loading a file *or* starting a repl. Am I
missing a method to support this, or should I go back to using
Script/Repl?
> I think a script like this should be included with the Clojure
> download. It's seems to me that everyone needs one and currently has
> to write their own by copying example script code from the Getting
> Started page.
Strongly agree. If 1.0 is released without this it would be a shame.
-Phil
> Maybe for scripts a global var such as *script-name* could be set
> automatically ?
I like this. I've also seen several requests for a way to know when
code is running in a script which could be satisfied by this as well.
This would be an easy change to clojure.main. I can make a patch.
Rich, will you accept this as an issue?
--Steve
> I like this. I've also seen several requests for a way to know when
> code is running in a script which could be satisfied by this as well.
For clarity, here's what I'm proposing based on recent discussion in
this thread:
[1] When clojure.main runs a script, it will set *command-line-script*
to the script name as it appears on the command line.
Example:
java -cp clojure.jar clojure.main -i dir-utils.clj list-
dir.clj :verbose :depth 3
will run with these values set:
*command-line-script* "list-dir.clj"
*command-line-args* (":verbose" ":depth" "3")
Note that dir-utils.clj is an "init file" here (there can be any
number of them, each introduced by a "-i"), while list-dir.clj is the
main script.
[2] When clojure.lang.Script runs a script, the name immediately
before either the end of line or the "--" will be the script name.
Here's the equivalent to above:
java -cp clojure.jar clojure.lang.Script dir-utils.clj list-dir.clj
-- :verbose :depth 3
(same values set):
*command-line-script* "list-dir.clj"
*command-line-args* (":verbose" ":depth" "3")
Note that in this case, files are still loaded in order, but "init"
files are not "marked". list-dir.clj is considered the main script
because it's the last to appear before the "--" which marks the
beginning of args.
[3] *command-line-script* will be nil in other cases: when
clojure.main launches a repl, when using clojure.lang.Repl, or when
clojure.main reads a script from *in*.
Comments welcome.
--Steve
I think this is a good idea.
It would also be useful for a .clj file to be able to determine if
itself is the main script or if instead it's being loaded some other
way (-i, load-file, require, etc.).
The proposed *command-line-script* could be used to make a good guess,
but since it's possible that the main script might have the same file
name as some lib, it wouldn't be perfect. I'm not exactly sure how
this ought to work, since the main script may not be a lib or even be
in the classpath. Maybe a dynamically-bound variable
*loading-main-script* that is bound to true when the main script is
loaded and specifically re-bound to false during lib loading?
--Chouser
It would also be useful for a .clj file to be able to determine if
itself is the main script or if instead it's being loaded some other
way (-i, load-file, require, etc.).