How to disable Leiningen "Repeatability" warning? - clojure

I have "snapshots" and "releases" repos defined in my ~/.lein/profiles.clj in order to avoid having to add these repos to each of the project.clj files in the many lein projects that I develop internally at work:
{:user {: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"}}}}
Of course, every time I run lein deploy in one of these internal projects, I get a warning:
:repositories detected in user-level profiles! [:user]
See https://github.com/technomancy/leiningen/wiki/Repeatability
I would like to suppress this warning, as I have intentionally set things up this way, and these projects cannot be "repeatably" built externally anyway.
Does anyone know how, or must I resort to reading the Leiningen source to figure this out?

The warning doesn't really have much to do with internal/external builds; the problem is that someone else attempting to build it even within your network will fail unless they replicate your ~/.lein/profiles.clj settings. That's bad.
However if you really insist on doing this, set the environment variable LEIN_SUPPRESS_USER_LEVEL_REPO_WARNINGS, as per https://github.com/technomancy/leiningen/blob/23b0804f672d2c4bb4ee9e37af302840dbe69440/leiningen-core/src/leiningen/core/project.clj#L542.

Related

Could not locate clojure/data/json: How do I get my REPL to see this (and similar) dependencies

I am using lein repl without a project so there is no project.clj.
I am running Leiningen 2.8.1 on Java 1.8.0_191 OpenJDK 64-Bit Server VM.
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory. Is that why I am getting a FileNotFoundException Could not locate clojure/data/json__init.class or clojure/data/js
on.clj on classpath? I can't find my other Clojure dependencies there either so I don't know where they reside and if this dependancy should be in .m2 or not.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck.
Is this a dependency that I still need to install? If so, how do I install it without going through a project?
I don't understand the JVM as I am new to it, so add a little extra information in your answer.
I have looked at this, this, this, this and this. I don't know if I am overlooking anything so your help will really be appreciated.
I am using lein run without a project so there is no project.clj.
If you're using Leiningen, this'll be much easier if you create a project.clj file that declares your dependencies. Leiningen will read project.clj and handle fetching any missing dependencies to your local Maven repository, and add them to your classpath when you start your REPL/application. (lein run doesn't work for me in a directory without a project.clj; I get an error: No :main namespace specified in project.clj.. Did you mean lein repl?)
When I require a Clojure dependency that I assume should just work - like clojure.data.json - I notice that it is not in my .m2 directory.
clojure.data.json doesn't ship with Clojure — it's a separate dependency that must be fetched and added to your classpath in order to use it. The classpath tells the JVM where to look when it loads class files. Leiningen will do both of these things for you if you declare the dependency in project.clj:
:dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/data.json "0.2.6"]]
You can also use the lein deps command if you only want to fetch dependencies.
You can create a new/blank Leiningen project with lein new project_name_goes_here. It will have a project.clj with a few boilerplate entries and a :dependencies key where you can declare dependencies.
I understand the error message but without knowing its location or even knowing how to properly add it to the CLASSPATH for the REPL to see it, I remain stuck. Is this a dependency that I still need to install? If so, how do I install it without going through a project?
You could manually download it from the internet, then manually add its path to your classpath, but if you're already using Leiningen it's much easier to add a line to a project.clj file and have Leiningen handle this for you.
If using a project.clj file w/Leiningen isn't an option, there are other ways to use Clojure and resolve dependencies/build a classpath at runtime. Boot accommodates this workflow, you can use Leiningen like this with a little added effort, as well as the newer tools.deps tooling. There are examples of each in this ClojureVerse thread, but note that some of these approaches are doing essentially the same thing as declaring the dependency in a file — instead declaring them as CLI arguments.
For example, using Clojure CLI tooling:
$ clj -Sdeps "{:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}}"
Clojure 1.9.0
user=> (require '[clojure.data.json :as json])
nil
user=> (json/write-str {:foo "bar"})
"{\"foo\":\"bar\"}"
user=> (System/getProperty "java.class.path")
"src:
/Users/me/.m2/repository/org/clojure/clojure/1.9.0/clojure-1.9.0.jar:
/Users/me/.m2/repository/org/clojure/data.json/0.2.6/data.json-0.2.6.jar:
/Users/me/.m2/repository/org/clojure/spec.alpha/0.1.143/spec.alpha-0.1.143.jar:
/Users/me/.m2/repository/org/clojure/core.specs.alpha/0.1.24/core.specs.alpha-0.1.24.jar"
You could create a deps.edn file containing {:deps {org.clojure/data.json {:mvn/version \"0.2.6\"}}} in the same directory, and clj would read that, resolve the dependencies if necessary, and build the classpath accordingly.
This is a great opportunity to use lein try. Once you add it to your ~/.lein/profiles.clj, you'd simply run: lein try org.clojure/data.json and you'll be greeted with a running REPL with that dependency just a require away.

(leiningen, s3-wagon-private) How to search for dependencies in private S3 repo?

I am trying to use the s3-wagon-private plugin. I have two lein projects:
X: a library I made for doing some data munging. Has some 3rd party dependencies.
Y: a library I made for working with my database, has X and some 3rd party dependencies.
I have the following in my ~/.lein/profiles.clj file:
{:repl {:dependencies [[org.clojure/tools.nrepl "0.2.12"]]}
:user {:plugins [[cider/cider-nrepl "0.10.0"]
[s3-wagon-private "1.2.0"]]
:signing {:gpg-key "0xabcdef12"}
:repositories [["private" {:url "s3p://acme/releases/"
:username :env
:passphrase :env}]]}}
When I run lein deploy private in project X, everything work just fine and it gets deployed to S3.
When I run lein deploy private in project Y, it complains about not being able to find project X.
Could not find artifact X:X:jar:0.7.0 in central (https://repo1.maven.org/maven2/)
Could not find artifact X:X:jar:0.7.0 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.
In other words, it is not looking in my private S3 repo to try to find project X. How do I solve this?
UPDATE: 2016-04-25
In a comment, Daniel Compton asked:
What happens when you run lein deps in project Y? From your error message, it looks like the repository "private" isn't present in project Y.
When I run lein deps in project Y, it does NOT give any errors:
(py3)aj-laptop:red aj$ lein deps
(:repositories detected in user-level profiles! [:user]
See https://github.com/technomancy/leiningen/wiki/Repeatability)
So I added the following to project.clj in project Y. This made lein deploy private work as expected:
:repositories [["private" {:url "s3p://acme/releases/"
:username :env
:passphrase :env}]]
So it seems that Project Y is not picking up :repositories from my ~/.lein/profiles.clj file. But Project X seems to pick it up just fine.
The issue is that the :repositories were specified in the user ~/.lein/profiles.clj file. Leiningen doesn't really like this. I suspect there is a latent bug here, perhaps in the interactions between Lein plugins and the dependency resolution system. Because it is generally not recommended to put :repositories in your user profile people may not have run into this before.
I think the best solution is probably to add :repositories to every file, annoying though that may be.

How can I conditionally load functionality in a clojure web-app

I have a clojure web app (standard ring handlers and compojure routes on a jetty server) for which I enabled live asset recompilation as middleware, which has been very very handy in development. As we get closer to production I would like to find a way not to load that code in production and instead read the pre-compiled assets (which I am able to generate as a lein task).
Currently the asset compilation machinery lives in the project code - it can be loaded from the lein task using eval-in-project, so I am able to reuse the same code in both places. However this means that the un-needed files are compiled and included in the production app.
The other issue is that there is one asset compilation tool I'm using that causes the app to fail to load at initialisation time if uberjar'ed since it makes use of native bindings to v8, which are not available (and not needed) when the precompiled assets are available.
How can I avoid loading this code in a production uberjar, but still benefit from dynamic re-compilation at run-time during development and testing?
Your :source-paths key in Leiningen decides which directories are checked for Clojure source code. With per-environment settings of :source-paths you can prevent unwanted namespaces from being included in your depoloyed uberjar.
The next piece of the puzzle is to ensure your code does not rely on the dev code on the production instance. This can be done with the help of the environ lib.
; excerpt of project.clj
(defproject your-org/your-project "version"
:source-paths ["src"] ; the main source location
:profiles {:dev {:source-paths ["dev-src"] ; added directory
:env {:dev "true"}}}
...)
; excerpt of project code for src/your_org/your_project.clj
(ns your-org.your-project
(:require environ.core :refer [env]))
(def maybe-launch-optional-thing
(if (= (env :dev) "true") ; checking a profile specific value
(do (require 'dev-only-dep.core)
(resolve 'dev-only-dep/launch))
(constantly nil))
...
(defn -main
[& args]
(maybe-launch-optional-thing)
...)
The if wrapped require, and the usage of resolve, ensure that this code is valid whether dev-only-dep.core is an available or not. maybe-launch-optional-thing is bound to the appropriate function in the optional namespace under a :dev profile, and is otherwise a no-op.

exclude certain clj namespaces from compilation in leiningen

I have a project that works fine using lein run. Now I want to compile it into a standalone jar using lein uberjar. However, there are a couple of source files in my src/projectname/ directory called e.g. playground.clj and stats.clj that I use for experimenting with emacs & the repl, but that I don't want to compile for the final project.
With something like make, I would specify all files that should be compiled. With clojure/leiningen, it seems, all files are compiled by default - how can I exclude files? I haven't found anything in the leiningen docs.
I am currently using :aot :all. Is this the place to change something? Again, I couldn't find detailed documentation on this.
UPDATE:
The suggestions so far haven't worked. What has worked, however, is to include all desired namespaces instead of excluding the ones that should not be compiled. E.g.:
(defproject myproject "version"
;; ...
:profiles {:uberjar {:aot [myproject.data
myproject.db
myproject.util]}})
Have a look at leiningen's sample project.clj, which describes how to use :jar-exclusions or :uberjar-exclusions to exclude arbitrary paths when creating jars (resp. uberjars).
;; Files with names matching any of these patterns will be excluded from jars.
:jar-exclusions [#"(?:^|/).svn/"]
;; Files with names matching any of these patterns will included in the jar
;; even if they'd be skipped otherwise.
:jar-inclusions [#"^\.ebextensions"]
;; Same as :jar-exclusions, but for uberjars.
:uberjar-exclusions [#"META-INF/DUMMY.SF"]
Old question, but I think I found the answer for those coming after me.
I found the answer in the link to the sample leiningen project from #amalloy's answer, except instead of :jar-exclusions I use source-paths, here.
The idea is to create two separate source directories, one for stuff you don't care to spread around and one for stuff you do:
dev-src/<your-project>/playground.clj
dev-src/<your-project>/stats.clj
src/<your-project>/<everything-else>
Then, in your project.clj, include src in source-paths normally, and include emacs-src in a special profile where your want it visible, say the usual :dev profile:
{
;; ...
:source-paths ["src"]
:profiles {
:dev {
:source-paths ["src" "dev-src"]
}
}
}
That way when you're messing around on your machine those files will be in the jar, and when you deploy to clojars or compile with uberjar they will not be included in the jar, nor compiled.
Try this (ns ^:skip-aot my-ns)
You can also do
(ns ^{:skip-aot true} my-ns
(require [...]))
Source

How do I add a library to LightTable so that when I use instarepl it will always have said library?

I'd like to add certain library dependencies to LightTable as a whole so that when I am messing around learning new stuff, I don't have to create a new project as a whole.
Let's say I want to always have access to these libraries: math.combinatorics and math.numeric-tower.
Lighttable seems to be calling a repl from leinigen, so am I really needing to add something there?
See https://github.com/LightTable/LightTable/blob/master/project.clj
It will be calling a repl of Leiningen. Rather than adding the dependencies to LightTable you could add them to your Leiningen Profile (~/.lein/profiles.clj)
The file would probably look something like this with your dependencies:
{:user {:dependencies [[math.combinatorics "x.x.x"]
[math.numeric-tower "x.x.x"]]}}
Generally this is not a very good idea. It will be a global thing and will probably cause you problems in the future. If you create an application you might find that these two libraries are available when they won't be for other people or on difference computers.
What would be a better option would be to create a new project using Leiningen. You can then edit your project.clj file to look something like this
(defproject math-thing "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[org.clojure/clojure "1.6.0"]
[math.combinatorics "x.x.x"]
[math.numeric-tower "x.x.x"]])
Then when editing your clj file LightTable uses your project.clj file to start instrepl and will resolve any needed dependencies.
Use the leiningen profile e.g. ~/.lein/profiles.clj and define a :injections [ ... ] node which performs the (require '[ ]) and import, refer-clojure and other items you have. I generally prefer to have at least Alembic present in my dev profile (wrapping Maven/Sonatype) so I can download, install in maven then classpath and project reload in one go using a macro/function wrapper around distill* to prevent a long load time due to too many libraries included in the user space. Pretty much this is the only function I usually want present in any REPL or LT InstaRepl and I put development and debugging snippets in project ./dev/user.clj to keep most of the messy stuff project specific.