4
votes

Newbie Clojure and leiningen question:

Given the code snippet in my project below, this works from the lein repl :

==> (-main "something")

produces the expected "Command: something ... running ... done" but doesn't work from the command line:

me pallet1]lein run "something"

produces "Command: something ... error: not resolved as a command"

Why? / how do I fix it?

To reproduce:

lein new eg

Then edit the generated project file, adding :main eg.core to define the main function, and edit the generated src/eg/core.clj file, and paste this in:

core.clj

(ns eg.core)
(defn something [] (println "Something!"))

(defn run-command-if-any [^String commandname]
    (printf "Command: %s ..." commandname)
    (if-let [cmd (ns-resolve *ns* (symbol commandname))] 
      (
        (println "running ...") (cmd) (println "done.")
      )
      (println "error: not resolved as a command.")
    ))
(defn -main [ commandname ] (run-command-if-any commandname))

Then

lein repl
eg.core=> (-main "something")

works (ie prints "Something!) , but lein run something doesn't (ie prints the "error: not resolved" message)

2
What is something? Where do you define it? If it's not in your clj file and your defined it in repl that running lein run doesn't know about it because it only reads your clj file. - Mikita Belahlazau
If run both code in REPL it gives me "not resolved". - Mikita Belahlazau
As Nikita says, you don't have repl/something defined in your example code. Also, even if you do define that, it'll give a NullPointerException since you're trying to call the result of (println "running") - Joost Diepenmaat
Okay, I added the defn of something to the code quote. The real code has several functions (to do with getting to grips with palletOps) my goal is to run one of them from the command line. - Chris F Carroll
I guess the alternative question I could have asked is "How do I pass the name of a Clojure function as a command line argument and have it run? The run-command-if-any is supposed to do that, but at the moment only works when I do it within the repl, not from the command line - Chris F Carroll

2 Answers

5
votes

The problem is that when you run it from lein your default namespace is "user" namespace:

(defn -main [ commandname ] (println *ns*))

Prints #<Namespace user>. So it doesn't contain something function because it is from another namespace. You have several choices:

  1. Pass fully qualified function name: your-namespace/something instead of something.
  2. Use your-namespace instead of *ns*: (ns-resolve 'your-namespace (symbol commandname))
  3. Change namespace to your-namespace in -main.

Example of method 3:

(defn -main [ commandname ] 
   (in-ns 'your-namespace)
   (run-command-if-any commandname))

Also you if you want to call several functions one by one you should use do:

(do (println "Hello")
    (println "World"))

Not just braces like ( (println "hello") (println "World"))

2
votes

the lein exec plugin is very useful for scripting such things in the context of a project. I have used this extensively for writing Jenkins jobs in clojure and other scripting situations

lein exec -pe '(something ...) (something-else) (save-results)'