In Leiningen configuration, how can I use environment variables to export the username? - clojure

This question is related to this previous
question.
I am able to install private Maven packages available on GitHub
packages with the following setting on project.clj:
...
:repositories {"releases" {:url "https://maven.pkg.github.com/my-organization-name/*"
:username "pdelfino"
:password :env}}
...
As you see, I can already use environment-variables for the
password, since it was set on my .zshrc file:
export LEIN_PASSWORD="my-personal-access-token-which-will-not-be-shared"
I would like to do the same for the username! This would be particularly important since other folks are working on this project.
I tried a few things, but none of them worked out. One example of documentation only illustrates how to do it with the password (using LEIN_PASSWORD - see here) but does not solve the username part. Executing lein help sample generates the same content previously mentioned.
How do I fix this?

As suggested by #cfrick in a comment, the solution was adding the snippet below on my .zshrc file, use the pointer on project.clj, and re-starting the terminal:
:repositories {"releases" {:url "https://maven.pkg.github.com/tallyfor/*"
:username :env/LEIN_USERNAME
:password :env/LEIN_PASSWORD}}
export LEIN_USERNAME="pdelfino"
export LEIN_PASSWORD="my-personal-access-token-which-will-not-be-shared"
I tried that earlier today. But, forgot to re-start the terminal (iTerm2).

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 to disable Leiningen "Repeatability" warning?

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.

lein-autodoc with Leiningen 2

I am attempting to use lein-autodoc, because I believe it to be the preferred documentation generator for Clojure. I have added :dev-dependencies [[lein-autodoc "0.9.0"]] to my project definition as per the instructions on the lein-autodoc github page.
Running lein deps runs without issue, however lein autodoc fails, claiming that autodoc is not a task.
I suspect the issue is that lein-autodoc is set up to work with leiningen 1. However, I'm using leiningen 2. Is there an alternate way I should be calling lein with autodoc? Or is the lein-autodoc package not set up to work with lein 2? If not, is there another preferred lein2-compatible documentation generation option?
EDIT:
After Cubic's hint below, I created ~/.lein/profiles.clj as follows:
{:user {:plugins [[lein-autodoc "0.9.0"]]}}
Now, running lein autodoc results in the following:
$ lein autodoc
Exception in thread "main" java.lang.IllegalAccessError: sh does not exist
at clojure.core$refer.doInvoke(core.clj:3778)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$load_lib.doInvoke(core.clj:5279)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$load_libs.doInvoke(core.clj:5298)
(...)
This suggests perhaps autodoc is not compatible with Lein 2? If not, is there any doc system that works with Lein 2?
autodoc used to be the more common documentation generator, but these days it is mostly just used for Clojure itself (and is optimized for the task). I highly recommend that you use codox instead. It is excellent. You can see it in action in one of my own projects here
(I know this has been said in the other answer, but for my answer to be complete I need to add it anyways)
Also, in leiningen 2 there is no :dev-dependencies key. Instead, there is a :dev profile. Take a look at the Leiningen profile documentation for more information. In this case, all you need to do is add a :plugins key to your project or global user profile with the plugins you want (like codox, autodoc, etc).
There is no :dev-dependencies in lein 2, you'd have to do it with profiles.
I'm not sure whether autodoc actually works with lein 2 though. Keep in mind that clojure and it's environment grows pretty fast, and there's lots of outdated information out there.

Using lwjgl in Leiningen/Clojure

Solution
(1) (println (. System getProperty "java.library.path"))
This gives me a list of places java looks for native extensions.
Then, I took the lwjgl native extensions, and put them there.
Things that didn't work for me (probably because I used them incorrectly)
(*) setting :native-path
(*) setting :native-dependencies
Problem
My setup:
(lein deps; echo "====="; cat project.clj; echo "====="; cat src/main.clj; echo "====="; lein repl) &> log
contents of "log"
Copying 10 files to /Volumes/ramdisk/fail/lib
=====
(defproject
mincase "0.0.1"
:dependencies [[org.clojure/clojure "1.4.0"]
[org.lwjgl.lwjgl/lwjgl "2.8.2"] ]
:repositories {"local" "/Users/x/z/maven_repo"}
:jvm-opts ["-Xms4g" "-Xmx4g"]
:repl-init main
)
=====
(ns main
(:import org.lwjgl.opengl.Display))
=====
REPL started; server listening on localhost port 31235
UnsatisfiedLinkError no lwjgl in java.library.path java.lang.ClassLoader.loadLibrary (ClassLoader.java:1860)
clojure.core=>
Note -- I had already done a "lein deps", so the lwjgl library has been pulled into maven. What I don't understand are:
(*) how do I get access to lwjgl from Clojure?
(*) more importantly, how do I debug which step this whole thing has gone wrong at?
$ find lib
lib
lib/clojure-1.4.0.jar
lib/jinput-2.0.5.jar
lib/jinput-platform-2.0.5-natives-linux.jar
lib/jinput-platform-2.0.5-natives-osx.jar
lib/jinput-platform-2.0.5-natives-windows.jar
lib/jutils-1.0.0.jar
lib/lwjgl-2.8.2.jar
lib/lwjgl-platform-2.8.2-natives-linux.jar
lib/lwjgl-platform-2.8.2-natives-osx.jar
lib/lwjgl-platform-2.8.2-natives-windows.jar
So it appears that lwjgl has been pulled in.
What are the steps I should try to figure out which step I went wrong on?
Thanks!
Dropping this note here since google found this post for my similar question.
The Leiningen folks have now addressed this: https://github.com/technomancy/leiningen/issues/898
If you get version 2.1.0 or later, it has the fix. See the bug for details.
UPDATE: (Aug 2013)
I have a project on github I use for experimentation with lwjgl here: https://github.com/rogerallen/hello_lwjgl
I'm also using LWJGL in my shadertone project here: https://github.com/overtone/shadertone
Because Shadertone is a library, I found I needed to package up the natives myself to get it to install reasonably for projects that depend on shadertone.
If anyone has some pull with the LWJGL folks, it sure would be nice if they just put natives into appropriate subdirectories as lein expects in their clojars releases.
Looks like a problem with your LD_LIBRARY_PATH. Are you including the correct .dll or .so files?
You probably need to add something like :native-dependencies [[lwjgl "2.8.2"]] to your project.clj.
Alternatively, you could try setting the right value from your shell:
export LD_LIBRARY_PATH=/home/username/lwjgl-2.8.2/native/linux/
It's a bit confusing why Display is refusing to import, though other classes in the same jar file import properly
(import '[org.lwjgl.opengl Util WindowsAWTGLCanvasPeerInfo])
I suspect that this jar file is broken, perhaps you could try a different version.
I tried debuggin this by running
cd lib
jar xf lwjgl-2.8.2.jar
cd org/lwjgl/opengl/
and then trying to load various classes i see there.
lein swank also does tab completion which can help in exploring classes without extracting them from the shell.
Ran into this today, solved it a bit differently by adding the native directory to :jvm-opts in project.clj:
(defproject projectname "0.0.1-SNAPSHOT"
:description "my project"
:jvm-opts ["-Djava.library.path=native/linux"]
:dependencies [[org.clojure/clojure "1.4.0"]])
I copied the jar files from the latest lwjgl release into lib and copied the native directory into the project root. Seems to work so far:
user=> (import org.lwjgl.opengl.Display)
org.lwjgl.opengl.Display
But I am only just getting started. Anyway, hope this helps someone else :)