To run Clojure files from command line, I'm using a zhs alias I added to my .zshrc:
alias 'clojure=java -cp /home/sinan/cclojure/lib/clojure-1.2.1.jar:/home/sinan/cclojure/lib/clojure-contrib-1.2.0.jar clojure.main -i '
With this, I can run my Clojure app like this:
clojure test3.clj
But it doesn't work when I want to send command line parameters.
➜ src clojure test3.clj arg1 arg2
Exception in thread "main" java.io.FileNotFoundException: arg1 (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:120)
at java.io.FileInputStream.<init>(FileInputStream.java:79)
at clojure.lang.Compiler.loadFile(Compiler.java:5817)
at clojure.main$load_script.invoke(main.clj:221)
at clojure.main$script_opt.invoke(main.clj:273)
at clojure.main$main.doInvoke(main.clj:354)
at clojure.lang.RestFn.invoke(RestFn.java:457)
at clojure.lang.Var.invoke(Var.java:377)
at clojure.lang.AFn.applyToHelper(AFn.java:172)
at clojure.lang.Var.applyTo(Var.java:482)
at clojure.main.main(main.java:37)
What am I doing wrong? Is my way of running Clojure apps wrong?
Thanks.
you just need to specify name of script, without -i key after clojure.main. In your case, clojure.main thinks, that test.clj is program to eval before (and it do it), while arg1 is script to execute
See description of option for clojure.main/main function
Related
I currently run a simple cli I wrote by calling: lein run my-cli-command arg --option
How can I call my command without needing to include lein run? This is what i'm after: my-cli-command arg --option
Do I need to convert it to an binary or executable and if so how?
As far as I know, there's no way to run just my-cli-command arg --option.
You can take lein out of the equation though by creating a Java archive:
lein uberjar
Then run the jar as you would any other:
java -jar target/my-cli-command-standalone.jar arg --option
uberjar will name the jar based on what you've called your project in project.clj, and will create a jar that relies on external dependencies, and one that doesn't (standalone).
Then, as #gary pointed out, you can stick the java - jar ... command in a .bat file, name it whatever you want, then run the bat directly. My bat-Fu is pretty weak, but there's likely a way to pass arguments to the bat and have them passed to the jar so you don't need to hard code the arguments.
As of Clojure 1.9 there are new CLI tools! See this guide for installation. You can create an executable script like this:
#!/usr/local/bin/clojure
(println "Hello World! from" *ns*)
(require '[clojure.walk :as walk])
(walk/postwalk-demo {:woo ::yeah})
Then make the script executable and execute it:
$ chmod +x my_script
$ ./my_script
Hello World! from #object[clojure.lang.Namespace 0x1ebea008 user]
Walked: :woo
Walked: :user/yeah
Walked: [:woo :user/yeah]
Walked: {:woo :user/yeah}
Start-up time seems improved as well. It takes a little over a second to run a trivial script (just print a string) on a recent MBP:
time ./hello
Hello World!
./hello 1.51s user 0.12s system 184% cpu 0.887 total
I've not used it, but I know inlein exists and it looks like what you need.
Inlein is the easiest and fastest way to run Clojure scripts. You only have to inline your dependencies, add in a shebang line, and make the script file executable.
And a minimal example:
#!/usr/bin/env inlein
'{:dependencies [[org.clojure/clojure "1.8.0"]]}
(println "hello world!")
You can use "binary payload" in shell script as described in https://coderwall.com/p/ssuaxa/how-to-make-a-jar-file-linux-executable
Basically you can concatenate a shell script and your uberjar in a single shell script file and execute java in the script specifying that script as the jar file on the classpath - the example comes from the linked post:
Save your runner script in stub.sh:
#!/bin/sh
MYSELF=`which "$0" 2>/dev/null`
[ $? -gt 0 -a -f "$0" ] && MYSELF="./$0"
java=java
if test -n "$JAVA_HOME"; then
java="$JAVA_HOME/bin/java"
fi
exec "$java" $java_args -jar $MYSELF "$#"
exit 1
Then concatenate it with your uberjar:
cat stub.sh my-cli-command-uberjar.jar > my-cli-command && chmod +x my-cli-command
Now you can run it directly:
./my-cli-command args...
There is also a lein plugin automating this process: lein-binplus
I tried following the ClojureScript quick start guide http://clojurescript.org/guides/quick-start and hit an NPE trying to manually invoke the clojurescript compiler on OS X.
I have java 1.8.0_92
% javac -version
javac 1.8.0_92
I made a new directory (for the sake of completeness ~/tmp/clojure/cljstest/). All paths are relative to this directory. I think I am using version 1.9.293 of clojurescript.
% cat $(which cljsc)
#!/bin/bash
exec java -jar /usr/local/Cellar/clojurescript/1.9.293/libexec/cljs.jar "$#"
The cljsc jar by itself, however, works fine.
% cljsc
Clojure 1.8.0
user=>
I also downloaded the standalone cljs.jar mentioned in the tutorial and checked the md5sum to make sure that they're the same.
% wget https://github.com/clojure/clojurescript/releases/download/r1.9.293/cljs.jar
% md5 cljs.jar
MD5 (cljs.jar) = 658d7b722cebe46e36604baf9eecfcb5
% md5 /usr/local/Cellar/clojurescript/1.9.293/libexec/cljs.jar
MD5 (/usr/local/Cellar/clojurescript/1.9.293/libexec/cljs.jar) = 658d7b722cebe46e36604baf9eecfcb5
I ran
% mkdir -p src/hello_world
and then
% touch ./src/hello_world/core.cljs
The contents of ./src/hello_world/core.cljs are:
(ns hello-world.core)
(enable-console-print!)
(println "Hello World!")
The contents of ./build.clj are:
(require 'cljs.build.api)
(cljs.build.api/build "src" {:output-to "out/main.js"})
I downloaded clojure through homebrew
% where cljsc
/usr/local/bin/cljsc
This is a shell script that I used to locate the .jar
% cat $(which cljsc)
#!/bin/bash
exec java -jar /usr/local/Cellar/clojurescript/1.9.293/libexec/cljs.jar "$#"
I tried running the compiler with the explicit classpath given in the tutorial
% java -cp /usr/local/Cellar/clojurescript/1.9.293/libexec/cljs.jar:src clojure.main build.clj
That produced the following stack trace:
% java -cp /usr/local/Cellar/clojurescript/1.9.293/libexec/cljs.jar:src clojure.main build.clj
Exception in thread "main" java.lang.NullPointerException, compiling:(/Users/gregnisbet/tmp/clojure/cljstest/build.clj:3:1)
at clojure.lang.Compiler.load(Compiler.java:7391)
at clojure.lang.Compiler.loadFile(Compiler.java:7317)
at clojure.main$load_script.invokeStatic(main.clj:275)
at clojure.main$script_opt.invokeStatic(main.clj:335)
at clojure.main$script_opt.invoke(main.clj:330)
at clojure.main$main.invokeStatic(main.clj:421)
at clojure.main$main.doInvoke(main.clj:384)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:379)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.NullPointerException
at cljs.closure$build.invokeStatic(closure.clj:1920)
at cljs.build.api$build.invokeStatic(api.clj:198)
at cljs.build.api$build.invoke(api.clj:187)
at cljs.build.api$build.invokeStatic(api.clj:190)
at cljs.build.api$build.invoke(api.clj:187)
at user$eval24.invokeStatic(build.clj:3)
at user$eval24.invoke(build.clj:3)
at clojure.lang.Compiler.eval(Compiler.java:6927)
at clojure.lang.Compiler.load(Compiler.java:7379)
... 11 more
I expected the clojurescript compiler to either produce main.js or give me a clojurescript-related error message. Why is the ClojureScript compiler throwing a NullPointerException? Is it a compiler bug?
Following the instructions in http://en.wikibooks.org/wiki/Compojure/Getting_Started, I:
downloaded http://github.com/weavejester/compojure/tarball/0.3.2
extracted to ~/compojure
chdir to there
changed permission to executable
run ant deps
ant
run export CLASSPATH=~/compojure/compojure.jar
created compojure shell script
Clojure source file
chdir to there
run ./compojure hello.clj
Then, I got:
Exception in thread "main" java.lang.NoClassDefFoundError: clojure/lang/Script
Caused by: java.lang.ClassNotFoundException: clojure.lang.Script
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
Could not find the main class: clojure.lang.Script. Program will exit.
I tried changing Compojure shell script to use full classpath, but still didn't work.
Why not? How to install Compojure?
That page is outdated.
You should follow these instructions from compojure developers:
https://github.com/weavejester/compojure/wiki/Getting-Started
I downloaded Clojure 1.2 https://github.com/downloads/clojure/clojure/clojure-1.2.0.zip , extracted it under /Library directory, created CLOJURE_HOME, added $CLOJURE_HOME/script to my $PATH.
When I'm trying to run clj or repl scripts that are located under script directory, I'm getting this error:
Exception in thread "main" java.lang.NoClassDefFoundError: jline/
ConsoleRunner
Caused by: java.lang.ClassNotFoundException: jline.ConsoleRunner
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Ok, jline.jar isn't in the CLASSPATH so I checked clj and repl scripts:
CLASSPATH=src/clj:test:test-classes:classes/:script/jline-0.9.94.jar:../clojure-contrib/target/clojure-contrib-1.2.0-SNAPSHOT.jar
if [ -z "$1" ]; then
exec java -server jline.ConsoleRunner clojure.main
else
SCRIPT=$(dirname $1)
export CLASSPATH=$SCRIPT/*:$SCRIPT:$CLASSPATH
exec java -Xmx3G -server clojure.main "$1" "$#"
fi
I downloaded jline.jar under $CLOJURE_HOME/script but I'm still getting the same error.
This lead me to the question:
What is the role of https://github.com/downloads/clojure/clojure/clojure-1.2.0.zip anyway?
Is it supposed to be used to install Clojure? or just to to build and get clojure.jar?
I noticed no one is talking about installing Clojure this way.
Am I missing something?
Clojure, being a JVM language, has to deal with the JVM classpath. This makes 'installing' it a bit unwieldy and confusing. Rather than install it yourself like this, try out some tools like cljr and cake. I wrote a blog post about this that might be helpful: http://blog.raynes.me/?p=48
In summary: Check out cljr, cake, and leiningen.
The majority of people in the Clojure community don't have Clojure 'installed'. Most people use a build tool and/or cljr. It doesn't make a lot of sense to install Clojure to a central place when, inevitably, you're going to need dependency management, and jars will be copied around everywhere anyway. In any case, it's much easier to let a tool handle the classpath for you.
the clojure.zip file exists so people who write tools will have a place for their tools to get the parts they need ;)
For people not writing tools they are either working on/with the latest branch from github and so they get Clojure with a git pull or they are using the above mentioned liningen, cake, cljr , counterclockwise(eclipse), la clojure (intellij), or netbeans.
I'm following the examples from the book 'Programming Clojure', and I'm at page
17 to run (require 'example.introduction).
I have set clojure at ~/bin/clojure as follows
java -server \
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8888 -cp ... clojure.lang.Repl
The -cp contains . (current directory). When I try it with clojure, I get the following error message.
Exception in thread "main" java.lang.ExceptionInInitializerError
at clojure.lang.Repl.(Repl.java:23)
Caused by: java.lang.RuntimeException: java.lang.NoSuchMethodError: clojure.lang.MultiFn.(Ljava/lang/String;Lclojure/lang/IFn;Ljava/lang/Object;Lclojure/lang/IRef;)V (utils.clj:0)
at clojure.lang.RT.(RT.java:290)
... 1 more
Caused by: java.lang.NoSuchMethodError: clojure.lang.MultiFn.(Ljava/lang/String;Lclojure/lang/IFn;Ljava/lang/Object;Lclojure/lang/IRef;)V (utils.clj:0)
at clojure.lang.Compiler.eval(Compiler.java:4153)
at clojure.lang.Compiler.load(Compiler.java:4470)
at clojure.lang.RT.loadResourceScript(RT.java:327)
at clojure.lang.RT.loadResourceScript(RT.java:316)
at clojure.lang.RT.load(RT.java:406)
at clojure.lang.RT.load(RT.java:376)
at clojure.core$load__4557$fn__4559.invoke(core.clj:3427)
at clojure.core$load__4557.doInvoke(core.clj:3426)
at clojure.lang.RestFn.invoke(RestFn.java:413)
at clojure.core$load_one__4520.invoke(core.clj:3271)
...
at clojure.lang.RT.loadResourceScript(RT.java:327)
at clojure.lang.RT.loadResourceScript(RT.java:312)
at clojure.lang.RT.maybeLoadResourceScript(RT.java:308)
at clojure.lang.RT.doInit(RT.java:430)
at clojure.lang.RT.(RT.java:286)
... 1 more
Caused by: java.lang.NoSuchMethodError: clojure.lang.MultiFn.(Ljava/lang/String;Lclojure/lang/IFn;Ljava/lang/Object;Lclojure/lang/IRef;)V
at clojure.contrib.duck_streams__init.load(Unknown Source)
at clojure.contrib.duck_streams__init.(Unknown Source)
...
at clojure.lang.Compiler.eval(Compiler.java:4142)
... 28 more
I tried to run clojure as follows.
alias clojure='java -jar $JARDIR/clojure.jar '
But it doesn't have the CLASSPATH that I setup in .bashrc correctly, when I run the command as follows.
(println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader))))
What might be wrong?
The easiest way is to use Stuart Halloway's code that accompanies the book:
Clone Stu's code from GitHub: $ git clone http://github.com/stuarthalloway/programming-clojure.git
cd into the programming-clojure directory that was created: $ cd programming-clojure
Run the repl.sh script in the bin/ directory: $ ./bin/repl.sh (make sure you run it from the repo root, not the bin/ directory, otherwise it won't work).
The script will set up all the necessary paths, including the paths to the examples in the book.
(You can do it manually, of course, but at any rate, you have to download or clone the programming-clojure source code anyway for the examples to work.)