We're trying to build our Clojure project with Leiningen. We've succeeded in creating an uberjar by doing the following:
preconditions:
project.clj file lists dependencies
:main my-project.core in project.clj
a core.clj file with a -main function
(:gen-class :main true) in core.clj
procedure:
ran lein test; completed with no failures
ran lein deps; completed successfully
from project.clj's directory: rain lein uberjar
This created two jar files: My-Project-1.0.0-SNAPSHOT-standalone.jar, and My-Project-1.0.0-SNAPSHOT.jar.
ran java -jar BioClojure-1.0.0-SNAPSHOT-standalone.jar, which resulted in this exception:
Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
My research into this problem has not been fruitful. Apparently, it's a known problem with no good solution. I do not understand the answers there.
What do we need to do to get our uberjar working?
determine which of our dependencies is causing the problem?
remove dependencies from our project?
compile the project some other way?
patch leiningen?
use the suggested command: zip *-standalone.jar -d META-INF/DUMMY.SF (I have no idea what this does)
do something with :uberjar-exclusions in the project.clj file? (if so, what?)
Lein and java versions:
$ lein version
Leiningen 1.6.1 on Java 1.6.0_26 Java HotSpot(TM) 64-Bit Server VM
Update: running the command suggested gives:
$ unzip -l BioClojure-1.0.0-SNAPSHOT-standalone.jar | grep -i -e "\.sf"
49911 08-27-09 15:57 META-INF/RCSB-PDB.SF
0 03-23-10 08:21 META-INF/maven/net.sf.alxa/
0 03-23-10 08:21 META-INF/maven/net.sf.alxa/jlatexmath/
929 03-23-10 08:20 META-INF/maven/net.sf.alxa/jlatexmath/pom.xml
115 03-21-10 14:01 META-INF/maven/net.sf.alxa/jlatexmath/pom.properties
175241 08-17-11 20:25 META-INF/SELFSIGN.SF
0 09-21-09 06:45 META-INF/maven/net.sf.opencsv/
0 09-21-09 06:45 META-INF/maven/net.sf.opencsv/opencsv/
5510 09-21-09 06:44 META-INF/maven/net.sf.opencsv/opencsv/pom.xml
106 09-21-09 06:45 META-INF/maven/net.sf.opencsv/opencsv/pom.properties
My understanding from reading the comments in that issue is that your problem would go away if you add the following to your project.clj
:uberjar-exclusions [#"foo.sf"]
where foo.sf is the particular .sf file you want to ignore from the jar. You can determine this by running:
unzip -l BioClojure-1.0.0-SNAPSHOT-standalone.jar | grep -i -e "\.sf"
The suggested zip command deletes the particular file from the jar (which is of the ZIP format).
Related
I created a new Leiningen project in idea, and imported some deps in project.clj as follows:
deps
and deps seems to be imported:
external libraries
But when I try to run repl, and required some deps that I imported in project.clj before, an FileNotFoundException has occurred:
FileNotFoundException
Starting nREPL server...
"E:\Program Files\Java\jdk-11.0.8\bin\java.exe" -Dfile.encoding=GBK -XX:-OmitStackTraceInFastThrow -Dclojure.compile.path=E:\idea_projects\clojure_test_second\target\classes -Dclojure_test_second.version=0.1.0-SNAPSHOT -Dclojure.debug=false "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=50688:D:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\bin" -classpath E:\idea_projects\clojure_test_second\test;E:\idea_projects\clojure_test_second\src;E:\idea_projects\clojure_test_second\dev-resources;E:\idea_projects\clojure_test_second\resources;E:\idea_projects\clojure_test_second\target\classes;C:\Users\asus\.m2\repository\org\clojure\clojure\1.10.1\clojure-1.10.1.jar;C:\Users\asus\.m2\repository\org\clojure\spec.alpha\0.2.176\spec.alpha-0.2.176.jar;C:\Users\asus\.m2\repository\org\clojure\core.specs.alpha\0.2.44\core.specs.alpha-0.2.44.jar;C:\Users\asus\.m2\repository\hiccup\hiccup\1.0.5\hiccup-1.0.5.jar;C:\Users\asus\.m2\repository\clojure\jdbc\clojure.jdbc\0.4.0\clojure.jdbc-0.4.0.jar;C:\Users\asus\.m2\repository\com\h2database\h2\1.4.193\h2-1.4.193.jar;C:\Users\asus\.m2\repository\nrepl\nrepl\0.6.0\nrepl-0.6.0.jar;C:\Users\asus\.m2\repository\clojure-complete\clojure-complete\0.2.5\clojure-complete-0.2.5.jar clojure.main -i C:\Users\asus\AppData\Local\Temp\form-init14732922726375964945.clj
Connecting to local nREPL server...
Clojure 1.10.1
nREPL server started on port 50817 on host 127.0.0.1 - nrepl://127.0.0.1:50817
(require '[clojure.java.jdbc :as jdbc])
Execution error (FileNotFoundException) at clojure-test-second.core/eval1555 (form-init14732922726375964945.clj:1).
Could not locate clojure/java/jdbc__init.class, clojure/java/jdbc.clj or clojure/java/jdbc.cljc on classpath.
jdk version is 11, idea version is 2021.1.3.
I searched solution for a long time, but didn't solve it. And I am a noob in clojure.
Thanks.
You have to
add [org.clojure/java.jdbc "0.7.12"] in project.clj file of your leiningen project folder. under :dependencies [ <add into this list> [org.clojure/java.jdbc "0.7.12"]].
Then you do $ lein deps from inside folder of your leiningen project folder, to ensure installation of that dependencies.
Then if you did M-x cider-jack-in from inside emacs opened inside project folder, you can do your require command. OR you just do $ lein repl from there and you can then do your (require '[clojure.java.jdbc :as j]) - voila!
Coming from Common Lisp, I was also quite lost like you.
Clojure requires Leiningen or Boot to function reasonably.
Whenever you have to install Clojure in a new machine, install first Leiningen, because you can install Cloure also using Leiningen.
With Boot, you can even create standalone scripts/executives which uses Clojure.
But also with Leiningen see here.
Install and use Boot
I think the way you want to use the repl - more freely -
suits more to Boot:
# install boot e.g. by (for linux)
$ sudo bash -c "cd /usr/local/bin && curl -fsSLo boot https://github.com/boot-clj/boot-bin/releases/download/latest/boot.sh && chmod 755 boot"
# upgrade!
$ boot -u
# create your project folders and move into toplevel
mkdir -p my-project/src
cd my-project
# then open repl
$ boot repl
;; within the repl:
;; declare resource-paths and dependencies
(set-env! :resource-paths #{"src"}
:dependencies '[[org.clojure/java.jdbc "0.7.12"]])
;; create a minimal project declaration
(task-options!
pom {:project 'my-project
:version "0.1.0"}
jar {:manifest {"Foo" "bar"}})
;; build the minimal project (to install the dependencies!)
(deftask build
"Build my project."
[]
(comp (pom) (jar) (install)))
;; call build
(build)
;; now, in the repl, you can do:
(require '[org.clojure/java.jdbc :as j])
Boot is more dynamic - since you can from the repl introduce dependencies and build.
I started using cloverage with leiningen. I want to excude calls to assert from the coverage report.
The following command works fine for me:
$ lein cloverage --exclude-call clojure.core/assert
However, when I put :cloverage {:exclude-call ["clojure.core/assert"]} into the project.clj file and I just call $ lein cloverage, then the parameter is ignored.
How should I configure cloverage from my leiningen project file?
EDIT: I understand that I could create an alias easily with the followings, however, I would prefer configuring it a cleaner way:
:aliases {"coverage" ["cloverage" "--exclude-call" "clojure.core/assert"]}
Hopefully you found a solution. For anyone coming across this post now:
I put the cloverage options under my test profile in my project.clj. So, you could try something like this in project.clj:
:profiles {:test {:cloverage {:exclude-call ["clojure.core/assert"]}}}
When I run cloverage from the command line, I have to do $ lein with-profile test cloverage.
Also, here's the post I used when figuring this out: Can I make lein cloverage skip specific tests?
I have just installed clojure 1.9 on my mac via Homebrew.
As expected I get 2 links in /usr/local/bin to the actual executables
clojure# -> ../Cellar/clojure/1.9.0.358/bin/clojure
clj# -> ../Cellar/clojure/1.9.0.358/bin/clj
running clojure from the command line works
$ clojure
Clojure 1.9.0
user=>
but for not for the command line tools
$ clj
zsh: command not found: clj.sh
both executable files exist
$ ls Cellar/clojure/1.9.0.358/bin
clj* clojure*
I've tried uninstalling clojure with brew uninstall and have deleted the cached version of clojure-tools-1.9.0.358.tar.gz in my ~/Library/Caches/Homebrew/ directory.
Installing it again was successful
$ brew install clojure
==> Downloading https://download.clojure.org/install/clojure-tools-1.9.0.358.tar.gz ####### 100.0%
==> ./install.sh /usr/local/Cellar/clojure/1.9.0.358
🍺 /usr/local/Cellar/clojure/1.9.0.358: 9 files, 19.4MB, built in 31 seconds
but still the same error.
Interestingly if I use the Finder to locate the file and double click on it, a new terminal window opens up and things seem to work.
Last login: Tue Mar 6 10:35:48 on ttys002
/usr/local/Cellar/clojure/1.9.0.358/bin/clj ; exit;
$ /usr/local/Cellar/clojure/1.9.0.358/bin/clj ; exit;
Clojure 1.9.0
user=>
Any ideas please on why this executable won't run directly from the command line?
Many thanks
The problem was that I'd set up an alias for clj in my shell profile file which referenced a shell script called clj.sh that I'd written but which no longer exists - hence why nothing happened except an error message.
Removing the alias from the shell profile file corrected the problem.
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'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.)