boot-clj / boot

Build tooling for Clojure.
https://boot-clj.github.io/
Eclipse Public License 1.0
1.75k stars 180 forks source link

Supplying CLI args "as is" #542

Open alexander-yakushev opened 7 years ago

alexander-yakushev commented 7 years ago

This is the followup on #374. Unfortunately, the issue I had is not resolved, because the new functionality seems to break when I provide arguments like --foo.

(deftask run []
  (println "Args passed:" *args*))
$ boot [ run --port 8080 ]
                              java.lang.Thread.run              Thread.java:  745
java.util.concurrent.ThreadPoolExecutor$Worker.run  ThreadPoolExecutor.java:  617
 java.util.concurrent.ThreadPoolExecutor.runWorker  ThreadPoolExecutor.java: 1142
               java.util.concurrent.FutureTask.run          FutureTask.java:  266
                                               ...                               
               clojure.core/binding-conveyor-fn/fn                 core.clj: 2020
                                 boot.core/boot/fn                 core.clj: 1030
                                               ...                               
                         boot.core/construct-tasks                 core.clj:  981
                                               ...                               
                         boot.core/construct-tasks                 core.clj:  988
java.lang.IllegalArgumentException: Unknown option: "--port"
        clojure.lang.ExceptionInfo: Unknown option: "--port"
    file: "/tmp/boot.user3615370981886979666.clj"
    line: 25

Is this the final behavior? It seems like I would have to continue using hacks just to have this very basic feature.

martinklepsch commented 6 years ago

The current behavior was introduced in https://github.com/boot-clj/boot/commit/afd0a1a3e8b827560e8e761c450488ea55d6cd6c

It supports an interesting hybrid mode like this:

(deftask run
  [x xtra FOO str "xtra"]
  (with-pass-thru _
    (prn :opts *opts* :args *args*)))
$ boot [ run -x test a b c d ]
:opts {:xtra "test"} :args ("a" "b" "c" "d")

meaning it still applies clojure.tools.cli to some of the arguments.

I'm kind of thinking that whenever a user goes as far as using the square bracket syntax they really don't want anything happening to their argvec but I'm not sure.

I have a change ready that would skip any clojure.tools.cli treatment if a task is called in [ task opts ] fashion if that's what we decide to go with. This would be a breaking change as people might rely on the hybrid mode. I doubt it's a lot of people but still.

alandipert commented 6 years ago

One option that comes to mind is use new delimiters to indicate "raw" arguments, but I can't think of any good options. My first thought was { task opts } but that only works for me in bash, and not in zsh.

Another option that comes to mind is a new syntax to indicate that a "normal" function should be called with no argument processing. Like this:

Function (defn main ...) in build.boot called like this:

$ boot @main hello foo

Qualified symbols's namespace is required and then the function is invoked with arguments:

$ boot @com.acme.tps-report/create x y z 1 2 3

martinklepsch commented 6 years ago

I kind of like the idea to have a syntax for invoking random functions.

@alexander-yakushev If you have a moment would you mind outlining how you intend to use tasks taking raw options? Will they be part of a pipeline or is it mostly about running one off script kind of things?

alexander-yakushev commented 6 years ago

Since I've created the initial issue (and this subsequent one) I've come to rely on this feature (more specifically, on my hack) less. I'm not sure anymore if that's an important feature. In any case, I'd say that if it exists in any variant, it should be the least complicated from the implementation standpoint.

alexander-yakushev commented 6 years ago

@martinklepsch The only usecase I have right now for this kind of feature is running the -main entrypoint to some large app that requires plenty of configuration, including CLI options. In other words, identical to lein run. For any other "dev time" tasks I don't need it as I expose them as Boot tasks instead, with Boot's own CLI parsing syntax.

So, to answer your exact question - yes, it's for one-off execution of app entrypoints (not scripts). For scripts I'm happy with boot.cli/defclifn.

larkery commented 6 years ago

I would also find a syntax for this useful. Either boot [run --foo] or boot @run --foo would work for me.