Next: Introduction, Previous: (dir), Up: (dir) [Contents][Index]
This is the defmain Reference Manual, version 0.12.1, generated automatically by Declt version 3.0 "Montgomery Scott" on Sun May 15 04:37:12 2022 GMT+0.
• Introduction | What defmain is all about | |
• Systems | The systems documentation | |
• Files | The files documentation | |
• Packages | The packages documentation | |
• Definitions | The symbols documentation | |
• Indexes | Concepts, functions, variables and data types |
Version: 0.12.1
Description: A wrapper around net.didierverna.clon which makes command line arguments parsing easier.
Licence: BSD
Author: Alexander Artemenko
Homepage: https://40ants.com/defmain
Bug tracker: https://github.com/40ants/defmain/issues
Source control: GIT
Library net.didierverna.clon
very powerful, but too complicated to use in simple cases. This library
provides a wrapper which will suite your needs in 80% cases.
Compare this code, which uses defmain
macro:
(defmain (main) ((debug "Show traceback instead of short message."
:flag t)
(log "Filename to write log to.")
(token "GitHub personal access token."
:env-var "TOKEN")
&rest repositories)
"Utility to analyze github forks."
;; Making real work
(loop for reporitory in repositories
do (analyze repository
:log log
:debug debug
:token token)))
With code providing the same functionality, but using raw
net.didierverna.clon
system:
(net.didierverna.clon:defsynopsis (:postfix "REPOSITORY")
(text :contents "This utility builds a report about all non-merged commits for any github repository. Just give some repository name like \"antirez/redis\" as an argument and pipe stdout to some file.")
(flag :short-name "h" :long-name "help"
:description "Print this help and exit.")
(flag :short-name "v" :long-name "version"
:description "Print version number and exit.")
(flag :long-name "debug"
:description "Show traceback instead of short message.")
(stropt :short-name "l" :long-name "log"
:description "Filename to write log to.")
(stropt :short-name "t" :long-name "token"
:env-var "TOKEN"
:description "GitHub personal access token."))
(defun main (&rest argv)
(declare (ignorable argv))
(net.didierverna.clon:make-context :cmdline (cons "12forks" argv))
(when (net.didierverna.clon:getopt :long-name "help")
(net.didierverna.clon:help)
(net.didierverna.clon:exit))
;; Making real work
(loop for reporitory in (remainder)
do (analyze repository
:log (net.didierverna.clon:getopt :long-name "log")
:debug (net.didierverna.clon:getopt :long-name "debug")
:token (net.didierverna.clon:getopt :long-name "token"))))
This system is available as part of the https://ultralisp.org distribution. Follow instruction
on the site to setup the distribution, and then install defmain
system using Quicklisp client:
(ql:quickload :defmain)
The main entry point for defining the main function for your program is the defmain
macro:
defmain:defmain
(name &key program-name) (&rest args) &body bodyThis macro let you to define a main function for a command-line program.
Usually the NAME
argument will be just MAIN
. This name will be bound
to a function which will process arguments and execute the BODY
.
ARGS
should contain an arguments definition. Each definition is a list of the form:
(NAME DESCRIPTION &KEY FLAG ENV-VAR SHORT DEFAULT)
Argument's NAME
should be a symbol. It names a variable which will be bound during
the BODY
execution. Also, this name is lowercased and used to form a --long
command line argument.
The lowercased first letter of the NAME
is used as a short version of the argument,
like -l
. But sometimes you might encounter duplication errors when having
a few arguments starting from the same letter. In this case provide SHORT
option,
to override the letter, used for the short option.
For example, here we have a conflict:
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output"))
...)
But we can tell defmain
(1
2
) to use -V
option for verbose, instead of -v
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output" :short "V"))
...)
Also, we can pass NIL
, to turn off short version for VERBOSE
argument:
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output" :short NIL))
...)
If some of your options are boolean, then give it a :FLAG t
option,
and a variable will become T
if user provided this flag on the command-line.
Also, you might want to specify a DEFAULT
value for the argument or provide
an environment variable name using ENV-VAR
. The value will be take from the
environment variable unless it was provided by the user on the command-line.
Arguments list of defmain
macro might end with &REST SOME-VAR
. In this case,
all unprocessed command line arguments will be collected into the SOME-VAR
list.
By default program name, shown in the --help
, will be the same as the name
of the function or taken as a third part of the ROS.SCRIPT.THIRD-PART
package
name, if you are using Roswell. However, you can override it providing the
PROGRAM-NAME
argument.
Also, you might want to build a more complex command-line interface with subcommands.
In this case, you need to use defmain
macro to define the main entry-point, and then
to define additional subcommands using defcommand
macro:
defmain:defcommand
(parent name) (&rest args) &body bodyThis macro is similar to defmain
macro in terms of arguments and body processing.
The only difference is that instead of the single name you have to provide a list of two names:
First element should be the name of the parent function. It can be either a main entry-point or other subcommand.
Second element is a symbol to name the subcommand.
Here is an example with of a program with two subcommands.
Pay attention to the MAIN
function's argument list.
It ends with a special symbol &SUBCOMMAND
. It should be
provided to let macro know there will be some subcommands
defined later.
(defmain (main) ((verbose "More detail in the output")
&subcommand)
...)
(defcommand (main upload) ((upstream "Repository name")
(force "Rewrite changes in case of conflict"
:flag t))
...)
(defcommand (main sync) ()
"Yet another subcommand."
...)
All arguments, specified for the MAIN
function also bound for all it's subcommands.
On command-line these arguments should preceed the subcommand's name
By default, main command run's specified subcommand and exits, but you can use it as a decorator, to execute some common code before and after as subcommand.
To run subcommand, execute subcommand
function:
(defmain (main) ((verbose "More detail in the output"))
(format t "Before subcommand.~%")
(defmain:subcommand)
(format t "After subcommand.~%"))
When writing more complex logic, these helpers could be useful:
defmain:print-help
Outputs to stdout a help about command line utility.
defmain:print-commands-help
Outputs information about supported subcommands.
It should be called from the function defined with defmain
macro.
defmain:get-subcommand-name
Returns a string with current subcommand's name.
It should be called from the function defined with defmain
macro.
defmain:subcommand
Executes the current subcommand. It is called automatically at the end of the main body unless you call it manually.
It can be called from the function defined with defmain
macro.
Make better support for integer arguments.
Support more types of arguments, like filepathes and enums.
Raise error when two short options are identical during
macro-expansion, not during runtime. Right now the clon
checks this during runtime:
Unhandled SIMPLE-ERROR in thread #<SB-THREAD:THREAD "main thread"
RUNNING {10005285B3}>:
Options #<LISPOBJ {1002705593}> and #<STROPT {1002705C03}>:
indentical short name "s".
Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING
{10005285B3}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<SIMPLE-ERROR "Options ~A and
~A: indentical short name ~S." {100277D8F3}> #<unused argument>
:QUIT T)
1: (SB-DEBUG::RUN-HOOK SB-EXT:*INVOKE-DEBUGGER-HOOK* #<SIMPLE-ERROR
"Options ~A and ~A: indentical short name ~S." {100277D8F3}>)
2: (INVOKE-DEBUGGER #<SIMPLE-ERROR "Options ~A and ~A: indentical short name ~S." {100277D8F3}>)
3: (ERROR "Options ~A and ~A: indentical short name ~S."
#<NET.DIDIERVERNA.CLON::LISPOBJ {1002705593}>
#<NET.DIDIERVERNA.CLON: :STROPT {1002705C03}> "s")
4: ((:METHOD NET.DIDIERVERNA.CLON::CHECK-NAME-CLASH
(NET.DIDIERVERNA.CLON::OPTION NET.DIDIERVERNA.CLON::OPTION))
#<NET.DIDIERVERNA.CLON::LISPOBJ {1002705593}>
#<NET.DIDIERVERNA.CLON::STROPT {1002705C03}>) [fast-method]
5: ((:METHOD INITIALIZE-INSTANCE :AFTER
(NET.DIDIERVERNA.CLON::CONTAINER)) #<NET.DIDIERVERNA.CLON::SYNOPSIS
{100270C013}>) [fast-method]
Next: Files, Previous: Introduction, Up: Top [Contents][Index]
The main system appears first, followed by any subsystem dependency.
• The defmain system | ||
• The defmain/defmain system | ||
• The defmain/changelog system |
Next: The defmain/defmain system, Previous: Systems, Up: Systems [Contents][Index]
Alexander Artemenko
(:git "https://github.com/40ants/defmain")
BSD
A wrapper around net.didierverna.clon which makes command line arguments parsing easier.
0.12.1
defmain.asd (file)
Next: The defmain/changelog system, Previous: The defmain system, Up: Systems [Contents][Index]
Alexander Artemenko
(:git "https://github.com/40ants/defmain")
BSD
defmain.asd (file)
file-type.lisp (file)
Previous: The defmain/defmain system, Up: Systems [Contents][Index]
Alexander Artemenko
(:git "https://github.com/40ants/defmain")
BSD
40ants-doc/changelog
defmain.asd (file)
file-type.lisp (file)
Files are sorted by type and then listed depth-first from the systems components trees.
• Lisp files |
• The defmain.asd file | ||
• The defmain/defmain/file-type.lisp file | ||
• The defmain/changelog/file-type.lisp file |
Next: The defmain/defmain/file-type․lisp file, Previous: Lisp files, Up: Lisp files [Contents][Index]
/home/quickref/quicklisp/dists/quicklisp/software/defmain-20220331-git/defmain.asd
Next: The defmain/changelog/file-type․lisp file, Previous: The defmain․asd file, Up: Lisp files [Contents][Index]
defmain/defmain (system)
defmain.lisp
Previous: The defmain/defmain/file-type․lisp file, Up: Lisp files [Contents][Index]
defmain/changelog (system)
changelog.lisp
@changelog (special variable)
Next: Definitions, Previous: Files, Up: Top [Contents][Index]
Packages are listed by definition order.
• The defmain package | ||
• The defmain/changelog package |
Next: The defmain/changelog package, Previous: Packages, Up: Packages [Contents][Index]
file-type.lisp (file)
defmain/defmain
common-lisp
Previous: The defmain package, Up: Packages [Contents][Index]
file-type.lisp (file)
common-lisp
@changelog (special variable)
Definitions are sorted by export status, category, package, and then by lexicographic order.
• Exported definitions | ||
• Internal definitions |
Next: Internal definitions, Previous: Definitions, Up: Definitions [Contents][Index]
• Exported special variables | ||
• Exported macros | ||
• Exported functions |
Next: Exported macros, Previous: Exported definitions, Up: Exported definitions [Contents][Index]
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
Next: Exported functions, Previous: Exported special variables, Up: Exported definitions [Contents][Index]
This macro is similar to DEFMAIN macro in terms of arguments and body processing.
The only difference is that instead of the single name you have to provide a
list of two names:
- First element should be the name of the parent function.
It can be either a main entry-point or other subcommand.
- Second element is a symbol to name the subcommand.
Here is an example with of a program with two subcommands.
Pay attention to the ‘MAIN‘ function’s argument list.
It ends with a special symbol &SUBCOMMAND. It should be
provided to let macro know there will be some subcommands
defined later.
“‘
(defmain (main) ((verbose "More detail in the output")
&subcommand)
...)
(defcommand (main upload) ((upstream "Repository name")
(force "Rewrite changes in case of conflict"
:flag t))
...)
(defcommand (main sync) ()
"Yet another subcommand."
...)
“‘
All arguments, specified for the ‘MAIN‘ function also bound for all it’s subcommands.
On command-line these arguments should preceed the subcommand’s name
By default, main command run’s specified subcommand and exits, but you can use
it as a decorator, to execute some common code before and after as subcommand.
To run subcommand, execute SUBCOMMAND function:
“‘
(defmain (main) ((verbose "More detail in the output"))
(format t "Before subcommand.~%")
(defmain:subcommand)
(format t "After subcommand.~%"))
“‘
file-type.lisp (file)
This macro let you to define a main function for a command-line program.
Usually the NAME argument will be just MAIN. This name will be bound
to a function which will process arguments and execute the BODY.
ARGS should contain an arguments definition. Each definition is a list of the form:
(NAME DESCRIPTION &KEY FLAG ENV-VAR SHORT DEFAULT)
Argument’s NAME should be a symbol. It names a variable which will be bound during
the BODY execution. Also, this name is lowercased and used to form a ‘–long‘
command line argument.
The lowercased first letter of the NAME is used as a short version of the argument,
like ‘-l‘. But sometimes you might encounter duplication errors when having
a few arguments starting from the same letter. In this case provide SHORT option,
to override the letter, used for the short option.
For example, here we have a conflict:
“‘
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output"))
...)
“‘
But we can tell DEFMAIN to use ‘-V‘ option for verbose, instead of ‘-v‘
“‘
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output" :short "V"))
...)
“‘
Also, we can pass NIL, to turn off short version for VERBOSE argument:
“‘
(defmain (main) ((version "Print program version and exit")
(verbose "Provide more detail on the output" :short NIL))
...)
“‘
If some of your options are boolean, then give it a ‘:FLAG t‘ option,
and a variable will become ‘T‘ if user provided this flag on the command-line.
Also, you might want to specify a DEFAULT value for the argument or provide
an environment variable name using ENV-VAR. The value will be take from the
environment variable unless it was provided by the user on the command-line.
Arguments list of DEFMAIN macro might end with ‘&REST SOME-VAR‘. In this case, all unprocessed command line arguments will be collected into the SOME-VAR list.
By default program name, shown in the ‘–help‘, will be the same as the name
of the function or taken as a third part of the ‘ROS.SCRIPT.THIRD-PART‘ package
name, if you are using Roswell. However, you can override it providing the
PROGRAM-NAME argument.
file-type.lisp (file)
Previous: Exported macros, Up: Exported definitions [Contents][Index]
Returns a string with current subcommand’s name.
It should be called from the function defined with DEFMAIN macro.
file-type.lisp (file)
Outputs information about supported subcommands.
It should be called from the function defined with DEFMAIN macro.
file-type.lisp (file)
Outputs to stdout a help about command line utility.
file-type.lisp (file)
Executes the current subcommand. It is called automatically at the end of the
main body unless you call it manually.
It can be called from the function defined with DEFMAIN macro.
file-type.lisp (file)
Previous: Exported definitions, Up: Definitions [Contents][Index]
• Internal special variables | ||
• Internal functions | ||
• Internal generic functions | ||
• Internal conditions | ||
• Internal classes |
Next: Internal functions, Previous: Internal definitions, Up: Internal definitions [Contents][Index]
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
Next: Internal generic functions, Previous: Internal special variables, Up: Internal definitions [Contents][Index]
file-type.lisp (file)
Checks if option :catch-errors t was given to the defmacro. If not given, then it is True by default.
file-type.lisp (file)
Outputs to stdout a help about command line utility.
file-type.lisp (file)
file-type.lisp (file)
Searches in the list of macro arguments a sequence like:
&parent-args (foo bar)
and returns (foo bar).
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
Takes a lambda list and returns a symbol, naming &rest argument, or nil.
file-type.lisp (file)
file-type.lisp (file)
If value is a bound symbol, then returns its bound value. For all other cases just returns a value itself.
file-type.lisp (file)
Returns t if there is &subcommand symbol in the list.
file-type.lisp (file)
file-type.lisp (file)
Returns a list of forms for "let" form.
Variable args contains a list of arguments given to defmain, like:
((debug :documentation "Show traceback instead of short message.")
(log :documentation "Filename to write log to.")
&rest repository)
For this input, output will be a list like:
((debug (net.didierverna.clon:getopt :long-name "debug"))
(log (net.didierverna.clon:getopt :long-name "log")))
file-type.lisp (file)
Returns a single fields description. Name argument is a symbol. Function returns a list.
file-type.lisp (file)
file-type.lisp (file)
Returns a list of forms for "let" form.
It is like make-bindings, but only returns bindings for positional arguments.
The should be separate because applied after the –help option was checked.
file-type.lisp (file)
file-type.lisp (file)
file-type.lisp (file)
Checks if there is &rest or &subcommand part in defmain’s args and outputs it either as
(:postfix "REPOSITORY") list
or as
(:postfix "SUBCOMMAND") list.
file-type.lisp (file)
Returns fields description for net.didierverna.clon:defsynopsis.
file-type.lisp (file)
Maps given function to all given args. Args should be in the format
of defmain arguments.
Returns a list of results from each function call.
file-type.lisp (file)
Next: Internal conditions, Previous: Internal functions, Up: Internal definitions [Contents][Index]
file-type.lisp (file)
A symbol of a function created by defmain macro. Used to extract information about the name of the current command and a name of subcommands.
file-type.lisp (file)
Next: Internal classes, Previous: Internal generic functions, Up: Internal definitions [Contents][Index]
file-type.lisp (file)
error (condition)
get-argument-name (method)
:name
get-argument-name (generic function)
Previous: Internal conditions, Up: Internal definitions [Contents][Index]
file-type.lisp (file)
synopsis (class)
A symbol of a function created by defmain macro. Used to extract information about the name of the current command and a name of subcommands.
:command
get-command (generic function)
Previous: Definitions, Up: Top [Contents][Index]
• Concept index | ||
• Function index | ||
• Variable index | ||
• Data type index |
Next: Function index, Previous: Indexes, Up: Indexes [Contents][Index]
Jump to: | D F L |
---|
Jump to: | D F L |
---|
Next: Variable index, Previous: Concept index, Up: Indexes [Contents][Index]
Jump to: | %
A D E F G I M P S |
---|
Jump to: | %
A D E F G I M P S |
---|
Next: Data type index, Previous: Function index, Up: Indexes [Contents][Index]
Jump to: | *
0
@
A C S |
---|
Jump to: | *
0
@
A C S |
---|
Previous: Variable index, Up: Indexes [Contents][Index]
Jump to: | A C D P S |
---|
Jump to: | A C D P S |
---|