I was reading about pallet here: http://twoguysarguing.wordpress.com/2010/11/01/starting-a-cluster-on-ec2-with-pallet/, as well as on the pallet site: http://palletops.com/. I'm still a little confused. The examples are arranged as if I'm expected to enter the code at a REPL.
But I think I'm missing something. Because I feel like (or I'm hoping) there should be some sort of lein support/integration, so that I can define some code to spin up a cluster, start the cluster, stop the cluster, deploy a war file, etc. via a series of lein commands.
I did find the following project on github, but it appears to be written to work with maven instead of lein: https://github.com/cemerick/clojure-web-deploy-conj.
And, this is very close to what I want, except that I want this tied into lein targets somehow: http://cemerick.com/2010/05/12/provisioning-administration-and-deployment-of-couchdb-java-tomcat/.
The Leiningen wiki refers to pallet/pallet-lein.
I don't have any experience with pallet, but it looks like the Leiningen plugin passes the first plugin argument to a function in the pallet.main namespace which appears to call into pallet.
So, the argument foo in lein pallet foo would be passed along to pallet.
So I found the following http://nakkaya.com/2010/02/25/writing-leiningen-plugins-101/, which describes the process for creating your own plugin. As it turns out it's fairly straightforward. Create a top level leiningen/ directory, give it a namespace name, and a function of the same name. And the function becomes a task in leiningen. So for example to provision a machine all I have to do is:
; In file leiningen/aws_provision.clj
(ns leiningen.aws-provision)
(defn aws-provision [project & args]
(println "pallet code to provision the box here..."))
Then from the lein prompt I can do:
lein aws-provision
I guess pallet-lein isn't going to really be able to do what I want, because the details of which cloud provider, which machine size, which packages to install on the machine, etc. will be different for each person.
Related
In Python world, whenever I need to try something I'd just make a new file a.py and insert the code that I want to try, and run it. This works because of the shebang line
#!/usr/bin/env python3
Which tells the os which interpreter to call for the file.
Is there an equivalent to this in clojure? I don't want to jump through all the hoops of running lein new app and specifying the main ns, everytime I just want to check out what a few lines of code does in a file.
Note that I already know about lein repl. And I tried to use that as the shebang
#!/usr/bin/lein repl
But this just brings up an error
No :main namespace specified in
project.clj.
If you have Clojure CLI tools installed, then you can use shebang scripts:
test.clj:
#!/usr/bin/env clj
(def x 10)
(println "x =" x)
In terminal:
chmod +x test.clj
./test.clj
Output:
x = 10
You can do this with boot. See https://github.com/boot-clj/boot/wiki/Scripts
Also, the ClojureVerse has a thread on this at https://clojureverse.org/t/scripting-with-clj/1618/5 where some options are being discussed.
Still, you should be aware that such an approach is probably not very useful. On the one hand you quite often want to manage dependencies on the other there's the startup time of the JVM, in particular when you need to compile some clojure sources first. If you need to run your script a few times because you're trying out thing, the startup time quickly becomes are real obstacle.
As an idea, I usually keep a leiningen project around for quick experiments. Here, I can adjust the dependencies as needed and quickly fire up a REPL to tinker with ideas and try out things. For me, it is not uncommon to find this REPL up and running and an Emacs already connected to it.
Strange problem, I know. So lein can be instructed to load a specific namespace when running the REPL with lein repl. That's great, let's assume I have a file called ns1.clj, so my project.clj file contains the line:
:repl-options {:init-ns ns1}
And, as expected, that file is loaded. However, I want to switch to another namespace (ns2) after ns1.clj does it's job, so I append the following to ns1.clj:
(ns ns2)
The problem is that Leiningen resets the REPL namespace to ns1 after the ns1.clj has finished. Is there any way to start the REPL by loading ns1.clj but not resetting the namespace post-load? By the way, I would assume that Leiningen should just execute the script and not set the namespace explicitly.
Background: I want to load a clj script and then switch to a namespace that has been loaded from an external source by that very script. So the logic in ns1.clj figures out what namespace should the REPL start in.
Based on your goal of wanting to extend repl functionality, I think you might do better to look at creating a lien plugin. You can then use this plugin without needing to modify your code and through your lein profiles, only have it installed when needed.
You might get some good ideas/pointers by looking at a number of existing lein plugins. In particular, there was quite an interesting blog post on planet clojure talking about a plugin called 'ultra' which extends the repl by adding ansi colours, improved test output formatting, enhanced stacktrace display and a few other repl tweaks. The project can be found on githug at https://www.github.com/venantius/ultra
How can I set it up, so that I can use Light Table on the Mac, connected to a Ubuntu-hosted nREPL, and create a new program/project.clj? Can anybody help me to understand what my approach should be, and where I'm going wrong?
I have a Ubuntu server, in VirtualBox, along with Leiningen, Pedestal, and a pedestal 'helloworld' sample program, that displays in a browser. I just can't connect to the same REPL that runs the helloworld program. I don't have client-side access or control to the server-side object.
I want to do client-server Clojure development from my Mac host LT, creating server-side programs, that I can view in a REPL.
I don't find LT to be intuitive in this area, and the advice I've read only suggests that LT will connect to an existing project/REPL. I want to create new objects, from the client
Assuming you are talking mostly about the server side of things (don't know much yet about ClojureScript), here is how you would setup a new project and code interactively against a remote repl.
lein new project-name in your VM.
Setup your project.clj the way you want it. You must include dependencies!
Start the REPL in your VM and note the port number
Commit your code to version control (git).
Checkout the same codebase for editing in LightTable in Mac OSX.
Connect to the remote REPL.
Open core.clj or create a new namespace file and start hacking.
Evaluate your code snippets or the entire file.
There are a couple of potential problems I foresee with this. First is that whenever you add a dependency, you will need to commit the change to version control, synchronize your VM working copy, restart your REPL, and reconnect LightTable to the remote REPL.
Second, you may have problems as the project grows beyond a few namespaces. I believe if your namespace requires another namespace from your project, the remote REPL process will (I think) try to load it off it's local classpath. If the dependency is not there or has changed, I don't think LightTable is smart enough to send the required namespaces over the wire. Try it out and let us know what the actual behavior is.
I'm new to Clojure, and after too much of my life have been already wasted on waiting for Leiningen to run my code, I'm trying to move to Cake. While Cake's persistent JVM loads up blazing fast - it presents a bigger problem - my functions are also persistent!
To demonstrate the problem, I've started a cake project(using cake new mess-up-with-cake), and wrote this in core.clj:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
)
(println "I'm in core.clj, not inside in any function")
And this is project.clj:
(defproject mess-up-with-cake "0.0.1-SNAPSHOT"
:description "TODO: add summary of your project"
:dependencies [[clojure "1.2.0"]])
(use 'mess-up-with-cake.core)
(deftask my-task
(println "I'm in my task")
(main-function)
)
When running it with cake my-task, I get:
I'm in core.clj, not inside in any function
I'm in my task
I'm in the main function
No surprise here.
Now, I've changed core.clj to this:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
(println "I've made a change in the main function")
)
(println "I'm in core.clj, not inside in any function")
(println "I've made a change outside the main function")
And when I run it, I get
I'm in core.clj, not inside in any function
I've made a change outside the main function
I'm in my task
I'm in the main function
core.clj was clearly reloaded, but the change I've made inside the main function was not printed! Only when I stop the JVM with cake kill and rerun it I get the desired result - but if I have to restart the JVM every time I change a function, I might as well go back to lein...
Any idea how to force cake to reload my functions(and only my functions - reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM..)?
This may not directly answer your question, though I hope it helps:
It sounds like your workflow if you where using leiningen would be to run:
lein run
wait for the JVM to start up .... get bored ...
observe result
edit code
repeat
This is a very common pattern in most languages and it's occasionally used for Clojure development (and Cake is very helpful here). It is much more common for Clojure development to use a single instance of the project and connect the editor to that instance using nrepl (or Slime and Swank). Because most everyone leaves the project running while they do the development not many people feel this pain and so the solutions are not as good in my opinion. Cake has largely been merged into Leiningen and the future direction of the Cake project is not clear to me (I could very well be wrong on this point). Of the Clojureians I know, all of them have moved to Leiningen and connect to their project from an editor like Emacs or vim.
a common workflow is:
start Emacs
M-x nrepl-jack-in
Ctrl-c Crtl-l to reload all the namespace and all it's dependent namespaces (this is close to a solution to your problem)
hack, load, repeat ;-)
This workflow is not Emacs or VI specific, the same method is used from Eclipse and Intelij
re: " reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM".
I find it to be no more than two seconds even with my larger projects
I used to struggle with the slow JVM startup speed as well, and had mixed success with Cake. You might want to take a look at the excellent autoexpect plugin for Leiningen, explained in some length in the author's blog post. Basically autoexpect reloads your code every time the working directory tree is updated (and evaluates any expect clause, reporting any test failures). Makes continuous testing a dream -- I sometimes have two shells going in Emacs -- one for the output of lein autoexpect, one for a connected REPL to send snippets of code to as the other poster is suggesting.
I like the continuous testing style so much I wrote a similar utility in Python for my non-Clojure development (described in this blog post) -- for Clojure, I use autoexpect.
I want to control a number of lein-plugins (lein-cljs build, lein-aws, lein-beanstalk) from my lein repl. Is there a way to do this?
For example, I want to be able to call
plugin/src/leiningen/cljsbuild.clj: once
from the repl -- however, I apparently can't (require 'leiningen.cljsbuild) into my lein repl.
Thanks!
I'm not sure if this addresses what you are actually trying to do, but do you know about lein interactive mode? EDIT: Since lein interactive doesn't exist in the new version of lein, the solution may be in some use of jark. Jark has an interactive mode and a plugin to use lein, so it may be possible to issue both lein commands and call clojure functions from a single interactive prompt.
The Vinyasa library claims to provide this functionality. At the time of this writing, vinyasa.lein is broken, but it may be fixed in the near future.