Clojure / Leiningen - package jar resource into clojars - clojure

I have a question similar to Deploy 3rd-party jar to clojars?
I've pushed a small project into clojars using lein deploy. That project relies on a jar dependency that I've simply put in a folder on the local drive and imported in my :resource-paths as per below:
(defproject cljblpapiwrapper "0.1.0-SNAPSHOT"
:description ""
:url ""
:license {:name "" :url ""}
:dependencies [[org.clojure/clojure "1.9.0"]]
:resource-paths ["resources/blpapi-3.8.8-2.jar"]
:repl-options {:init-ns cljblpapiwrapper.core})
Now upon importing my deployed clojars repo in another project, it fails to find classes within the jar repo. I'm getting this trace:
#error {
:cause com.bloomberglp.blpapi.CorrelationID
:via
[{:type clojure.lang.Compiler$CompilerException
:message java.lang.ClassNotFoundException: com.bloomberglp.blpapi.CorrelationID, compiling:(cljblpapiwrapper/core.clj:6:1)
:at [clojure.lang.Compiler load Compiler.java 7526]}
{:type java.lang.ClassNotFoundException
:message com.bloomberglp.blpapi.CorrelationID
:at [java.net.URLClassLoader findClass URLClassLoader.java 382]}]
:trace
[[java.net.URLClassLoader findClass URLClassLoader.java 382]
[clojure.lang.DynamicClassLoader findClass DynamicClassLoader.java 69]
[java.lang.ClassLoader loadClass ClassLoader.java 424]
[clojure.lang.DynamicClassLoader loadClass DynamicClassLoader.java 77]
[java.lang.ClassLoader loadClass ClassLoader.java 357]
...
Looks to me like the jar didn't make it to clojars - how can I package it within my repo? Alternatively, how can I push it separately to clojars?
thanks,

Did you try to download your lib from clojars? Use the jar command to unpack the *.jar file and see if the lib is there.
Look at this repo: https://github.com/cloojure/tupelo-datomic
In the ./resources dir there is a jar file: datomic-free-0.9.5661-everything.jar
You may need to play around with the syntax in project.clj to make the uberjar on clojars form correctly. You may need to publish the dependency JAR file on a separate maven-compatible repo. Options include:
Deps.co - Created by the host of The REPL podcast
AWS S3 - there is a lein plugin to help with this

I think you need to bind the jar as dependency in your project.clj, resource path tells uber jar just include the file.

Related

Leiningen: working with local git repo

I want to change something in incanter, so I created a fork on github and a clone of it on my laptop. Now, when I try to run tests with lein test I get these errors:
/Users/me/work/incanter$ lein test
Could not find artifact incanter:incanter-core:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-io:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-charts:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-mongodb:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-pdf:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-svg:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-latex:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-excel:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-sql:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
Could not find artifact incanter:incanter-zoo:jar:1.5.8-SNAPSHOT in clojars (https://clojars.org/repo/)
This could be due to a typo in :dependencies or network issues.
If you are behind a proxy, try setting the 'http_proxy' environment variable.
/Users/me/work/incanter$
I have not changed anything in the project.clj yet, here it is:
(defproject incanter "1.5.8-SNAPSHOT"
:description "Incanter is a Clojure-based, R-like statistical programming and data visualization environment."
:url "http://incanter.org/"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:scm {:name "git" :url "https://github.com/incanter/incanter"}
:min-lein-version "2.0.0"
:dependencies [[incanter/incanter-core "1.5.8-SNAPSHOT"]
[incanter/incanter-io "1.5.8-SNAPSHOT"]
[incanter/incanter-charts "1.5.8-SNAPSHOT"]
[incanter/incanter-mongodb "1.5.8-SNAPSHOT"]
[incanter/incanter-pdf "1.5.8-SNAPSHOT"]
[incanter/incanter-svg "1.5.8-SNAPSHOT"]
[incanter/incanter-latex "1.5.8-SNAPSHOT"]
[incanter/incanter-excel "1.5.8-SNAPSHOT"]
[incanter/incanter-sql "1.5.8-SNAPSHOT"]
[incanter/incanter-zoo "1.5.8-SNAPSHOT"]
[org.clojure/clojure "1.5.1"]
]
:profiles {:dev {:resource-paths ["data"]}
:debug {:debug true}
:uberjar {:aot :all
:main incanter.main
:dependencies [[reply "0.3.0" :exclusions [org.clojure/clojure]]
[swingrepl "1.3.0"
:exclusions [org.clojure/clojure org.clojure/clojure-contrib]]
]
}
}
:repl-options {:init-ns incanter.irepl
:resource-paths ["data"]
:init (do
(set! *print-length* 500)
(use 'clojure.repl))
}
:jvm-opts ["-Xmx1g" "-Djsse.enableSNIExtension=false"
~(str "-Dincanter.home=" (System/getProperty "user.dir"))]
)
Any help will be greatly appreciated.
I took a look at the project. You must build any projects under /modules so that the snapshot-version 1.5.8-SNAPSHOT will be builded on your local .m2/
cd modules
cd incanter-core
lein install
...
Then I think it should work. Alternative you can reduce in the dependencies to 1.5.7.
You can use this approach:
Create jars of those projects(lein uberjar)
Then use command for each your jar:
mvn install:install-file \
-Dfile=maven_repository/my-project.jar \ ;;path to your jar(this is example)
-DgroupId= incanter \
-DartifactId= incanter \
-Dversion=0.1.0 \
-Dpackaging=jar \
-DgeneratePom=true
Then add deps to your project.clj and refresh leiningen:
[incanter/incanter "0.1.0"]
[groupId/artifactId "your-version"]
...

Leiningen missing test resources?

Leiningen provides a default directory for 'main' code, main resources, and test code, but nothing for test resources.
Coming from a maven background this is something I'd expect.
In that case, where should test resources live? Or a larger question, what's the philosophical reason why it wouldn't need a test resources directory
Test resources in Leiningen are managed using profiles. To set up a directory with test resources, you would add its path to the :resource-paths property of the :test profile (to make it available only to the test task) or :dev profile (to make it available to all dev tasks, e.g. test, run, repl, etc.)
Sample project.clj for a Maven-like project structure:
(defproject myproject "0.0.1-SNAPSHOT"
:source-paths ["src/main/clj"]
:test-paths ["src/test/clj"]
:resource-paths ["src/main/resources"]
:dev {:resource-paths ["src/test/resources"]})
When the :dev profile is active, its :resource-paths values are merged with the :resource-paths from the base project, giving you what you're looking for.
See the Leiningen docs for more information on profiles.

slf4j File Not Found error when building uberwar

I would like to understand why my Ring application is attempting to open the log file at compile time.
I have a webservice in Compojure and Ring. The application works without issue but whenever I compile the application to an uberwar or run lein ring server I get the below error from slf4j.
I don't understand what is causing the Clojure compiler to attempt to access this log file during compilation. The only clue which I have is that it only started happening when I included the Korma library.
If I create the directory I can get rid of the error, however, I want to understand why the application is attempting to open the log file at compile time.
log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: /var/log/ege/myservice/myservice.log (No such file or directory)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:133)
at org.apache.log4j.FileAppender.setFile(FileAppender.java:294)
at org.apache.log4j.RollingFileAppender.setFile(RollingFileAppender.java:207)
at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:165)
at org.apache.log4j.config.PropertySetter.activate(PropertySetter.java:307)
at org.apache.log4j.config.PropertySetter.setProperties(PropertySetter.java:172)
at org.apache.log4j.config.PropertySetter.setProperties(PropertySetter.java:104)
at org.apache.log4j.PropertyConfigurator.parseAppender(PropertyConfigurator.java:809)
at org.apache.log4j.PropertyConfigurator.parseCategory(PropertyConfigurator.java:735)
at org.apache.log4j.PropertyConfigurator.configureRootCategory(PropertyConfigurator.java:615)
at org.apache.log4j.PropertyConfigurator.doConfigure(PropertyConfigurator.java:502)
log4j configuration is a runtime configuration of your app. Korma uses log4j configuration for its usage in runtime. So, it's not surprising that when running lein ring server, korma uses log4j configuration for its logging and the log4j logging throws error cause it can not find the log directory.
As for the error thrown during lein check or lein ring war. Maybe you have some forms which attempts to connect to database or even do some query to your database in top-level of some of your namespaces.
maybe you have something like this:
(ns my-app.db
(:use korma.db)
(:use korma.core))
(def db (create-db (mysql {:db "my_db"
:user "root"
:password ""})))
;; this form below attempts to get a db connection
(def conn (get-connection db))
(defentity users)
;; this form below attempts to query the database
(select users)
when clojure compiles, it executes every form, thus, clojure connects to db or query the db. In other words, clojure runs a part of your app during compilation.
unrelated note
Everything above aside, you should separate the log4j configuration or any other runtime-configs for development environment and production environment.
I usually separate development environment and production environment configuration using :profiles in project.clj.
:profiles
{:production
{:ring
{:open-browser? false, :stacktraces? false, :auto-reload? false}
:source-paths ["prod-config"]}
:dev
{:dependencies [[ring-mock "0.1.5"] [ring/ring-devel "1.3.1"]]
:source-paths ["dev-config"]}}
I put my development's log4j.properties in dev-config dir and production's log4j.properties in prod-config dir.

Issue with lein ring uberjar and profiles

I am having troubles to make lein ring uberjar work with multiple profiles.
The following works:
lein new luminus profile-issue
cd profile-issue
lein ring uberjar
java -jar target\profile-issue-0.1.0-SNAPSHOT-standalone.jar
Now, when working with multiple profiles the following change to project.clj is important.
;add key to project.clj
:target-path "target/%s/"
Next attempt
lein clean
lein ring uberjar
java -jar target\profile-issue-0.1.0-SNAPSHOT-standalone.jar
Error: Could not find or load main class profile_issue.handler.main
The reason why it's important to split the target path into subdirectories when working with multiple profiles is explained here, around line 250. In a nutshell, when using :target-path "target/ you'll end up in troubles because different profiles compile into the same directory and when you start the REPL without a lein clean, you don't really know what you get.
And btw, when using :target-path "target/%s/" the jar and uberjar don't end up in the same directory which is weird.
Any idea?

How to configure Leiningen to use a corporate repository?

We are hosting a corporate repository which acts as a proxy to the well-known repositories (e.g. Maven Central and Clojars). I want Leiningen to hit the corporate repository in the first place. Only when the corporate repository fails to deliver the artifact Leiningen should ask the standard repositories. This should be the default behaviour of all my projects. What configuration I have to do?
I have added the corporate repository as a mirror in ~/.lein/profiles.clj:
{:user {:mirrors {"our-repo" {:name "our-repo"
:url "http://our-repo/all/"}}}}
Unfortunately this setting has no impact. Leiningen downloads the artifacts from Maven Central:
PS> lein repl
Retrieving org/clojure/clojure/1.5.1/clojure-1.5.1.pom from central
...
Update
xsc suggests to overwrite the Maven Central repository with a mirror definition which points to the corporate repository. It works. Now instead of going to the external Maven Repository Leiningen retrieves the artifacts from the corporate repository.
S/He also suggests to specify an additional repository definition to install a fallback mechanism.
Unfortunately this does not work so well because Leiningen complains about this setting:
:repositories detected in user-level profiles! [:user]
See https://github.com/technomancy/leiningen/wiki/Repeatability
This warning is very annoying. For this reason I would abstain from this setting. Is there another way to install a fallback mechanism?
Here's what works for me:
{:user {:mirrors {#".+" {:url "http://nexus.example.com:8081/nexus/content/groups/public"}}
:repositories [["snapshots" {:id "NudaySnapshots"
:url "http://nexus.example.com:8081/nexus/content/repositories/snapshots"}]
["releases" {:id "NudayReleases"
:url "http://nexus.example.com:8081/nexus/content/repositories/releases"
:sign-releases false}]]}
:auth {:repository-auth {#"nexus.example.com" {:username "deployment"
:password "foo bar baz"}}}}
This handles both resolving dependencies through my Nexus mirror and publishing artifacts to it with lein deploy.
I get the annoying "Repeatability" warning, but I'm working on getting rid of that.
As far as I can see in Leiningen's example project.clj you have to use the name of the repository to mirror as the key in the :mirrors map. So, try this:
{:mirrors {"central" { ... }}}
This will most likely replace the repository completely, so you might want to add the original again:
{:mirrors {"central" {:url "..." }}
:repositories {"maven" {:url "http://repo1.maven.org/maven2/"}}}