exclude certain clj namespaces from compilation in leiningen - clojure

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

Related

Is there a way to add a second src folder to leiningen?

I am trying to generate documentation for my source code using a templating library.
Currently my directory structure looks like
---src
---test
---project.clj
I would like to make a third folder called docs, in addition to src and test, which will have my documentation related namespaces. I would like to only include the namespaces in src in my final uberjar. I tried simply adding a third folder. I ran the repl and then required my docgen namespace in the docs folder, but got the following error.
(require '[<>.<>.docgen :as docgen] :reload)
FileNotFoundException Could not locate <>/<>/docgen__init.class or foundry/schema/docgen.clj on classpath. clojure.lang.RT.load (RT.java:456)
Is there a way to add the docs folder to the classpath of a certain profile so it is not part of uberjar?
Solved:
Added a profile in my project.clj, with the source-paths key. I use the with-profile lein command with +docgen
:profiles {
:docgen {
:dependencies [[]]
:source-paths ["docs"]
}
}

Distributing a simple library via clojars

I have implemented a hyphenation algorithm (at namespace hyphenator-clj.core), defined it as org.clojars.nikonyrh.hyphenator-clj 0.1.0 at defproject and pushed it to Clojars. Uberjar seems to have files like core__init.class, core.clj and core.class.
However when I try to use it as a dependency on an other project I get this error:
$ lein uberjar
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.pom from clojars
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.jar from clojars
Compiling example.core
java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
Exception in thread "main" java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3657)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
...
Must I change my project's folder structure so that it matches the expected org/clojars/nikonyrh/hyphenator_clj__init.class, or can I somehow override the current behavior? If there is a good tutorial about this out there I would be happy to read it.
Basically I would like to get this example project to work. project.clj:
(defproject example "0.0.1-SNAPSHOT"
:description ""
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojars.nikonyrh.hyphenator-clj "0.1.0"]]
:javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"]
:aot [example.core]
:main example.core)
src/example/core.clj:
(ns example.core
(:require [org.clojars.nikonyrh.hyphenator-clj :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))
I'm suspecting I also have the english.txt in a wrong directory, as it isn't contained in the uberjar but resource files are an other topic.
You would probably be better off not using a hyphen in the namespace hyphenator-clj. Why not just use hyphenator? But if you do I suspect that the name of the directory should have an underscore in it rather than a hyphen, so be: hyphenator_clj.
If fixing that issue doesn't help then another thing to look out for, which I can't see from your question, is where exactly is core.clj in the directory structure, and does the project.clj reflect that? For instance is the path for the namespace hyphenator-clj.core in a src directory off the root of your project? The root of your project being defined as where the project.clj is located.
Something else that would be good to see in the question is whether you can get the program to work just locally, without having packed it up into an uberjar and shipped it to clojars. My guess would be that it does work locally, but it would help for that to be stated.
Okay taking a look at your links now. You might like to read a working project deployed to clojars, that has hypens in its name, for instance here. The first difference you might notice is the project name you use is rather long: org.clojars.nikonyrh.hyphenator-clj. It should just be hyphenator-clj. Also I would recommend having an identifier ending in "-SNAPSHOT" as that project does.
But taking a look at the bigger picture, a great idea you suggested in the comments is to test without Clojars being in the mix at all. To do this use lein install on the library you want to use from another lein project.
Ahaa at least I understand the process a bit better now, basically my require has to match the structure of the used JAR file, which may be very different from the project's name. For example cc.qbits/spandex is actually required as qbits.spandex.
The english.txt dependency was fixed by moving it to resources folder, deploying the new version to Clojars and importing the dependency as it exists in the JAR:
(ns example.core
(:require [hyphenator-clj.core :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))

lein - how to use a downloaded library

Let's say I find a cool clojure library like https://github.com/clojurewerkz/buffy
Now I want to use it. And it only lives on github.
How do I do this? I would love a full start to finish hello world example.
I've read about compiling it as a jar and using that, or using :dependencies in my project.clj but so far no examples have been complete, and I'm new.
For example in python I'd git clone the repo into the root of my working tree and any file could just say import buffy
I just learned this five minutes ago. I wanted to use the clojure-csv library, here's what I did using Leiningen
Make a new leiningen project
lein new app csvtest
Now I have a folder called csvtest/. In the csvtest/project.clj file, edit the dependencies section to add the clojure-csv github path and a version. I'm not quite sure how the versioning works to be honest:
:dependencies [[org.clojure/clojure "1.5.1"]
[clojure-csv/clojure-csv "2.0.1"]]
Now run lein deps to automagically download any unresolved dependencies for your project
$ lein deps
...
Retrieving clojure-csv/clojure-csv/2.0.1/clojure-csv-2.0.1.pom from clojars
...
Now edit csvtest/src/csvtest/core.clj. Make it look like this:
Edit: (Based on sveri's comment I changed :use closjure-csv.core to the :require line)
(ns csvtest.core
(:gen-class)
(:require [clojure-csv.core :refer [parse-csv]]))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println (parse-csv "1,2,3,hello,world")))
You have to add the (:require [clojure-csv.core :refer [parse-csv]]) line to your ns, and in main it calls parse-csv, one of the functions provided by the library. From reading, it looks like :use is depreciated in favor of :require.
Note: For anyone coming from python (like me), it looks like doing :use clojure-csv.core is akin to from closure_csv import *, which is bad practice in python as well. And (:require [clojure-csv.core :refer [parse-csv]]) is like from clojure_csv import parse_csv
Run the project with lein run. My output was
$ lein run
([1 2 3 hello world])
I hope that helps!
You can download/use it from Clojars.
Clojars link:
https://clojars.org/clojurewerkz/buffy
To use it with Leiningen, add this to your dependencies(on project.clj file):
[clojurewerkz/buffy "1.0.0-beta4"]
After that, you can run lein deps from your project root folder in order to download dependencies.
To use dependencies directly from Github repos, you can check out this: https://github.com/tobyhede/lein-git-deps
Using lein (which is Clojure's build tool) you have a project.clj file. if you do lein new project-name you get a new project named "project-name", with a project.clj file in it. look at that file, you will see a :dependencies entry in it as in this example:
:dependencies [[org.clojure/clojure "1.5.1"]]
all you must do to include buffy, is look at their github site, and find out which version to use, then you add it to the :dependecies list:
:dependencies [[org.clojure/clojure "1.5.1"]
[clojurewerkz/buffy "1.0.0-beta3"]]
now you can simply do lein deps which will download the dependencies and once you written your code lein run to actually run it.
read a little about lein and check out its sample project.clj file to get a better understanding of how you should use clojure.

create multiple uberjars in leiningen

I want to create a number of uberjars with different main entrypoints from a single codebase. I see you can specify the main namespace as an argument to lein uberjar but I don't see a way to specify the resulting filename or path, so they'll just overwrite one another. Is there a way to override the output filename or path from the command line?
Or is there a better way of doing this? Have separate project files that all reference a central "library" project? If so, what would the physical structure of this look like and how to get it to build?
You can use multiple Leiningen profiles to accomplish what you are talking about.
(defproject project1 "0.1.0-SNAPSHOT"
:description "Something Amazing!"
:dependencies [[org.clojure/clojure "1.5.1"]]
:profiles {:v1 {:main project1.core1
:uberjar-name "uberjar1.jar"}
:v2 {:main project1.core2
:uberjar-name "uberjar2.jar"}
:v3 {:main project1.core3
:uberjar-name "uberjar3.jar"}})
And, you can build them with:
$ lein with-profile v1:v2:v3 uberjar
Here is an annotated reference source where you can find an option for specifying a name of your output jar or uberjar file and any other options that may be set in a project.clj file.
;;; Jar Output
;; Name of the jar file produced. Will be placed inside :target-path.
;; Including %s will splice the project version into the filename.
:jar-name "sample.jar"
;; As above, but for uberjar.
:uberjar-name "sample-standalone.jar"

Error building clojure project with lein

I'm not at all familiar with clojure, and I have the source for a project that I'm trying to build. The project has a project.clj file, which google says means I should use the lein build tool. However:
$ lein compile #lein jar does the same thing
Exception in thread "main" java.lang.RuntimeException: java.io.FileNotFoundException: Could not locate testui/core__init.class oCompiling testui.core
r testui/core.clj on classpath
I suspect that project.clj may be broken. core.clj is located in src/com/foodient/semanticanalysis/testui, and project.clj looks like this:
(defproject testui "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[org.clojure/clojure "1.3.0"]
[org.apache.poi/poi "3.8-beta4"]
[gate-clj "1.0.0"]]
:aot [testui.core]
:main testui.core
:run-aliases {:test testui.core/-main})
Any ideas?
If you set up a lein project and the name has that Clojuristic dash in it, like bene-csv (one of mine), then lein new bene-csv creates several directories and ./bene-csv/project.clj. My core.clj is located in ./bene-csv/src/bene_csv/core.clj. Note the dash is dropped in bene_csv in favor of an underscore.
As to your problem more than likely core.clj is not located where lein expects it, which should be ./testui/src/testui/core.clj. I hope this helps.
I think the issue is that the core.clj is not in the right directory. It should be in the src/testui directory.
My guess is that you should change references to your code from
testui.core
to
com.foodient.semanticanalysis.testui.core
The reason for it is that the part of a namespace before the last dot corresponds to a package name (this term comes from java and jvm)
You indicated that your sources are in:
src/com/foodient/semanticanalysis/testui
so the package name is com.foodient.semanticanalysis.testui
You should probably also update the namespace declaration in your clojure source files to match this convention (or move your source to src/testui).
Hope it helps.