{"id":19031469,"url":"https://github.com/plandes/clj-actioncli","last_synced_at":"2026-05-03T07:30:19.033Z","repository":{"id":80107468,"uuid":"62923278","full_name":"plandes/clj-actioncli","owner":"plandes","description":"An action oriented framework to the CLI (and various other libraries)","archived":false,"fork":false,"pushed_at":"2020-03-02T23:07:25.000Z","size":204,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-02T04:14:38.587Z","etag":null,"topics":["clojure","command-line","library"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/plandes.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-07-08T23:40:26.000Z","updated_at":"2020-03-02T23:07:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"b01048e9-508c-4b1e-85a1-93d38a1d414d","html_url":"https://github.com/plandes/clj-actioncli","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plandes%2Fclj-actioncli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plandes%2Fclj-actioncli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plandes%2Fclj-actioncli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plandes%2Fclj-actioncli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/plandes","download_url":"https://codeload.github.com/plandes/clj-actioncli/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240080768,"owners_count":19744924,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","command-line","library"],"created_at":"2024-11-08T21:23:46.211Z","updated_at":"2026-05-03T07:30:18.989Z","avatar_url":"https://github.com/plandes.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Command line interface action oriented framework\n\n[![Travis CI Build Status][travis-badge]][travis-link]\n\n  [travis-link]: https://travis-ci.org/plandes/clj-actioncli\n  [travis-badge]: https://travis-ci.org/plandes/clj-actioncli.svg?branch=master\n\nThis library parses *action based* command line arguments and invokes the\ncorresponding code.  Action based means using the first token (after the binary\nname) as a mnemonic to invoke some action much like `clone` in `git clone`.\n\nEach action mnemonic is mapped to a function with corresponding arguments\npassed at invocation time.\n\nThis package has a few other basic utility libraries that is used by this\npackage but useful for many others (i.e. file system path register and\nresolution).\n\n\u003c!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc --\u003e\n## Table of Contents\n\n- [Obtaining](#obtaining)\n- [Documentation](#documentation)\n- [Templating](#templating)\n- [Usage](#usage)\n    - [Action Commands](#action-commands)\n        - [src/com/example/service.clj](#srccomexampleserviceclj)\n        - [src/com/example/core.clj](#srccomexamplecoreclj)\n        - [resources/service-log4j.xml](#resourcesservice-log4jxml)\n    - [Executing](#executing)\n    - [Resource Location](#resource-location)\n    - [Resource Functions](#resource-functions)\n    - [Resource Lexical Scope](#resource-lexical-scope)\n    - [Timeout Block](#timeout-block)\n- [Building](#building)\n- [Changelog](#changelog)\n- [License](#license)\n\n\u003c!-- markdown-toc end --\u003e\n\n\n## Obtaining\n\nIn your `project.clj` file, add:\n\n[![Clojars Project](http://clojars.org/com.zensols.tools/actioncli/latest-version.svg)](http://clojars.org/com.zensols.tools/actioncli/)\n\n\n## Documentation\n\nAPI documentation:\n* [Clojure](https://plandes.github.io/clj-actioncli/codox/index.html)\n* [Java](https://plandes.github.io/clj-actioncli/apidocs/index.html)\n\n\n## Templating\n\nYou can use the [make project](https://github.com/plandes/clj-mkproj) utility\nwith the [lein project](https://github.com/plandes/template/tree/master/lein)\ndirectory to template out the files in the following secion.\n\n\n## Usage\n\nThis API provides not only an enhanced action based command line, but also\nseveral general purpose libraries.\n\n\n### Action Commands\n\nSay you're writing a web service (among other things an uberjar might have) and\nyou want to start it with the command:\n```shell\n$ java -jar serviceapp.jar service -p 8080\n```\n\nThere are three kinds of action commands:\n\n* **Global action:** These are parsed first before anything else and usually\n  trigger an early exit.  Example options include `--help`, `-h`, `--version`.\n* **Single action:** These don't include the name of the action on the command\n  line and are typical UNIX like command lines.  Examples include `ls`, `grep`,\n  etc.\n* **Multi-action:** These include the an action name (think operand) at the\n  beginning of the command line.  Examples include `git clone` where `clone` is\n  the action name.\n\n\nCreate the following files: service.clj and core.clj\n#### src/com/example/service.clj\n```clojure\n(ns com.example.service\n  (:require [clojure.tools.logging :as log])\n  (:require [zensols.actioncli.parse :refer (with-exception)]))\n\n(defn run-server [port]\n  (log/infof \"starting service on port %d\" port))\n\n(def start-server-command\n  {:description \"start the guide website and service\" \n   :options [[\"-p\" \"--port PORT\" \"the port bind for web site/service\"\n              :default 8080\n              :parse-fn #(Integer/parseInt %)\n              :validate [#(\u003c 0 % 0x10000) \"Must be a number between 0 and 65536\"]]]\n   :app (fn [opts \u0026 args]\n          (with-exception\n            (run-server (:port opts))))})\n```\n\n#### src/com/example/core.clj\n```clojure\n(ns com.example.core\n  (:require [zensols.actioncli.parse :as parse]\n            [zensols.actioncli.log4j2 :as lu])\n  (:require [example.version])\n  (:gen-class :main true))\n\n(defn- version-info-action []\n  (println (format \"%s (%s)\" example.version/version example.version/gitref)))\n\n(defn- create-action-context []\n  (parse/multi-action-context\n   '((:service com.example.service start-server-action)\n     (:repl zensols.actioncli.repl repl-action))\n   :version-option (parse/version-option version-info-action)\n   :default-arguments [\"service\" \"-p\" \"8080\"]))\n\n(defn -main [\u0026 args]\n  (lu/configure \"service-log4j2.xml\")\n  (parse/set-program-name \"nlpserver\")\n  (-\u003e (create-action-context)\n      (parse/process-arguments args)))\n```\n\n#### resources/service-log4j.xml\n```xml\n\u003cconfiguration status=\"OFF\"\u003e\n    \u003cappenders\u003e\n        \u003cconsole name=\"console\" target=\"SYSTEM_OUT\"\u003e\n            \u003cpatternLayout pattern=\"%c{1}: %m%n\"/\u003e\n        \u003c/console\u003e\n    \u003c/appenders\u003e\n    \u003cloggers\u003e\n        \u003clogger name=\"com.example\" level=\"info\"/\u003e\n        \u003croot level=\"warn\"\u003e\n            \u003cappenderRef ref=\"console\"/\u003e\n        \u003c/root\u003e\n    \u003c/loggers\u003e\n\u003c/configuration\u003e\n```\n\n### Executing\n```bash\n$ java -jar target/clj-actioncli-example-0.1.0-SNAPSHOT-standalone.jar --help\nservice\tstart the guide website and service\n  -p, --port PORT  8080  the port bind for web site/service\n\n repl\tstart a repl either on the command line or headless with -h\n  -h, --headless  start an nREPL server\n  -p, --port      the port bind for the repl server\n\n version\tGet the version of the application.\n  -g, --gitref\n\n$ java -jar exampleapp-standalone.jar version\n0.0.1\n$ java -jar exampleapp-standalone.jar version -g\n0.0.1\n\u003csome git ref\u003e\n$ java -jar exampleapp-standalone.jar service -p 1234\nJul 08, 2016 6:09:08 PM clojure.tools.logging$eval1$fn__5 invoke\nINFO: starting service on port 1234\n$ java -jar exampleapp-standalone.jar repl\nnetwork-repl\nClojure 1.8.0\nuser=\u003e (+ 1 1)\n2\n```\n\n\n### Resource Location\n\nMany apps (command line) need to find paths on the file system.  This library\nprovides a way to both register and refine those locations with Java system\nproperties.\n\n```clojure\nuser=\u003e (require '[zensols.actioncli.resource :as res])\nuser=\u003e (res/register-resource :data :system-file \"data\" :system-default \"../data\")\n#function[zensols.actioncli.resource/eval9492/fn--9493]\nuser=\u003e (res/register-resource :runtime-gen :pre-path :data :system-file \"db\")\n#function[zensols.actioncli.resource/eval9498/fn--9499]\nuser=\u003e (.getPath (res/resource-path :data))\n../data\nuser=\u003e (.getPath (res/resource-path :runtime-gen))\n../data/db\nuser=\u003e (res/set-resource-property-format \"myapp.%s\")\n\"myapp.%s\"\nuser=\u003e (System/setProperty \"myapp.data\" \"/new-data-path\")\nnil\nuser=\u003e (.getPath (res/resource-path :data))\n../new-data-path\nuser=\u003e (.getPath (res/resource-path :runtime-gen))\n../new-data-path/db\n```\n\n### Resource from the Class Path\n\nWhen creating resources from the Java class path (i.e. file system and jar\nagnostic locations), use `:resource` for the `:type` and `:constant` for the\nresource without a leading forward slash.  For example:\n\n```clojure\n(register-resource :root-pkg :constant \"pool\" :type :resource)\n```\n\n\n### Resource Functions\n\nYou can also declare functions to resolve your resources.  If using\n`resource-path` with an argument (i.e. additional directory) the function is\ncalled with an argument.  Otherwise none is given and the 0-arg function form\nis called.  For example:\n\n```clojure\n(register-resource :func-dir\n                   :function (fn\n                               ([] (io/file \"no-file-for-you\"))\n                               ([file]\n                                 (io/file \"/another/path\" file))))\n(resource-path :func-dir \"pos\")\n=\u003e #object[java.io.File 0x394b51a \"/another/path/pos\"]\n```\n\n\n### Resource Lexical Scope\n\nYou can temporarily register and then call `resource-path` in a lexical scope\nusing `with-resources` as in:\n\n```clojure\n(with-resources\n  (register-resource :data :system-file \"../less-data\")\n  (resource-path :runtime-gen))\n\n=\u003e #object[java.io.File 0x1bbdf16d \"../less-data/db\"]\n```\n\n\n### Timeout Block\n\nThere's a utility namespace that throws an exception if a lexical scope takes\ntoo long to process.  For example, the following will throw a\n`java.util.concurrent.TimeoutException`:\n\n```clojure\n(require '[zensols.actioncli.util :refer (with-timeout)])\n\n(with-timeout (* 1 1000)\n  (Thread/sleep (* 2 1000)))\n\n=\u003e TimeoutException Execution timed out.  clojail.core/thunk-timeout (core.clj:41)\n```\n\n\n## Building\n\nTo build from source, do the folling:\n\n- Install [Leiningen](http://leiningen.org) (this is just a script)\n- Install [GNU make](https://www.gnu.org/software/make/)\n- Install [Git](https://git-scm.com)\n- Download the source: `git clone --recurse-submodules https://github.com/plandes/clj-actioncli \u0026\u0026 cd clj-actioncli`\n- Build and install: `make install`\n\nNote that you can also build a single jar file with all the dependencies with: `make uber`\n\n\n## Changelog\n\nAn extensive changelog is available [here](CHANGELOG.md).\n\n\n## License\n\nCopyright © 2017, 2018 Paul Landes\n\nApache License version 2.0\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplandes%2Fclj-actioncli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplandes%2Fclj-actioncli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplandes%2Fclj-actioncli/lists"}