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.
Related
I currently have a setup for my Clojure project which allows me to toggle configuration from dev to test or prod by configuring profiles in Leiningen's project map. The section related to the profiles looks like this:
:main ^:skip-aot myproject.core
:target-path "target/%s"
:profiles {:uberjar {:aot :all}
:dev {:env {:clj-env :development
:database-uri "jdbc:postgresql://localhost:5432/db_dev"}}
:test {:env {:clj-env :test
:database-uri "jdbc:postgresql://localhost:5432/db_test"}}
:production {:env {:clj-env :production
:database-uri "jdbc:postgresql://localhost:5432/db"}}})
The issue is I would further like to enhance this and be able to toggle between multiple mains. I have seen in other posts that people usually achieve this by configuring the profiles like here.
What I don't know how to do is how to preserve the configuration I have so that profiles correspond to environments but also further configure it in order to be able to choose the main class by simply adding a parameter to lein run.
I have figured out that one way is obviously to keep having just one main class and add that multiplexing with actual Clojure code, but I was hoping to be able to do it via lein configuration.
After trying multiple options, the only way I have found to do this is via aliases.
First setting the :main option to nil, so the MANIFEST.MF doesn't have any Main.class set, and then simply adding a couple of aliases specifying which main class to run.
:main nil
:target-path "target/%s"
:aliases {"main1" ["run" "-m" "project.main1.core"]
"main2" ["run" "-m" "project.main2.core"]}
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.
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?
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/"}}}
We have some 3rd-party jars checked-in to our project. We'd like to add them to the classpath. That's it. We don't want to set up a local maven repo (because that would break our 'check out and run' philosophy). Each developer would have to set up their own maven repo, distinct from the project.
Is there a way to do this or is this? Most of the answers I've seen say to set up a local maven which we don't want or need just to add a jar to a classpath.
You will need to setup a local maven repository, but that can be a simple directory, in your project directory, that you then check in to source control. (Which will maintain your 'check out and run' policy)
As of Leiningen 2.2.0 the functionality to deploy jars is built-in with the lein deploy task. So, the task has simplified from previous versions.
Create a directory inside your project called, in this example, myrepo. (The name is arbitrary)
Add a :repositories entry in your project.clj file with a path to the local directory you created.
:repositories [["localrepo1" "file:myrepo"]]
Deploy your free floating jar to the repo.
lein deploy localrepo1 com.blueant/fancypants 1.0.1 fancypants.jar
And, add your dependency to your project.clj :dependencies vector as normal.
:dependencies [[com.blueant/fancypants "1.0.1"]]
The deploy task will generate the checksums and directory structure required to to tie into the lein dependency resolution. You can verify your jar is loaded correctly with the lein deps :tree command.
Note: File paths in :repositories are formatted as URLs. So, /Users/user1/Desktop is file:///Users/user1/Desktop, and, a local directory within the project, myrepo is file:myrepo.
I'd like to elaborate on #Jared314's excellent answer that helped me as well.
Below is a script that automates the process of adding multiple jars from a local lib folder to a local repository:
#!/bin/sh
export LOCALREPO_USERNAME=
export LOCALREPO_PASSWORD=
for file in lib/*.jar
do
name=$(basename "$file")
basename=${name%.jar}
echo "Deploying $basename"
artifactId="local/$basename"
lein deploy localrepo1 $artifactId 1.0 $file
echo "[$artifactId \"1.0\"]" >> dependencies.log
done
The list of Leiningen dependencies that can be added to project.clj is stored in dependencies.log.
Before running the script, :repositories entry in project.clj has to be updated to allow for reading repository username and password from the environment:
:repositories [["localrepo1" {:url "file:myrepo"
:username :env/localrepo_username
:password :env/localrepo_password}]]
This will prevent the repository password prompt from displaying when running the script.
This question has already been answered here.
It is indeed possible, but there's a reason why maven and dependency management exists. If you have many dependencies changing versions creating a repo is the recommended approach.