deploy command line

1.0.0

A simple command line option interface for applications used with Deploy.

Table of Contents

About deploy-command-line

This is a simple command line arguments handling system to quickly extend your program shipped with Deploy and provide a set of extra commands that users might find useful.

How To

While not strictly necessary, it is expected that your application will make use of Deploy to be turned into a standalone binary. You can then make your system's :entry-point be org.shirakumo.deploy.command-line:toplevel to hook into the command line processing, or manually call it from your own entry point as desired.

By default only one command is defined, help, and a number of help sections are also defined for you based on information that ASDF and Deploy know about.

In order to define commands you can make use of define-command and define-class-command. It'll look much like a standard defun though with some extra metadata to handle the parsing of the arguments, help, and so on. Let's take a look at an example:

(command-line:define-command eval (&key ((load :load :l) NIL pathname "A file to load")
                                        ((print :print :p) NIL boolean "Whether to print the results of the forms")
                                        ((verbose :verbose :v) NIL boolean "Whether to print the forms being executed")
                                        &rest (forms NIL "Lisp forms to evaluate"))
  :aliases ("e" "evaluate")
  :help "Evaluate an arbitrary Lisp form. May be useful for debugging purposes. Only advisable if you know exactly what you're doing!"
  (when load
    (when verbose (format *query-io* "~&; Loading ~a~%" load))
    (load load :verbose verbose))
  (dolist (form forms)
    (with-input-from-string (stream form)
      (loop for form = (read stream NIL #1='#:EOF)
            until (eq form #1#)
            do (when verbose (format *query-io* "~&; Evaluating ~a~%" load))
               (let ((values (multiple-value-list (eval form))))
                 (when print (format *query-io* "~{~&~a~%~}" values)))))))

This defines a command named eval that has three key arguments (&key) and takes an arbitrary number of arguments afterwards (&rest). The key arguments each have aliases (:load :l) so that the user can specify a shorter name on the command line too. Further, the key arguments are parsed according to their respective types (pathname) and have a help string ("A file to load").

Then we define alias names for the command itself ("e" "evaluate"), along with a help string (:help ...), and finally we actually define the code to run when the command is invoked.

The syntax for arguments in commands is as you expect, with required arguments, &optional, &key, and &rest all supported. All of those can be further specified to provide the extra metadata for the command line interface however, in the very least to provide the type name and help string.

On the command line itself, the order of arguments for required, optional, and rest arguments must be the same as specified in the lambda-list. However, all of those can be interspersed with key arguments. Keyword arguments also follow "standard" Unix command line syntax, with long keys requiring two dashes (--foo) and single-character keys requiring a single dash (-f). In the single dash case you can also bunch multiple keys together (-fbz). If a key's value has the type boolean it is treated as a flag and when present on the command line, the value of the key argument is the inverse of its default. Otherwise the key expects another argument immediately after, which is treated as the key's value (--foo value).

If you need to extend the types of arguments that can be parsed, you can do so by adding methods to parse-command-line-type, and should you need to manually invoke commands, you can do so with invoke-command.

For more low-level management, you can set or remove commands via the command accessor, and set the default command used if no command is provided by the user via *default-command*. All commands are named by case-insensitive strings. Trying to define another command with the same name as another will replace the previous command.

Finally, the default help command will either display help specific to another command, or a general overview in the style of Unix manual pages. Depending on the information in your system definition, the following sections will be provided, corresponding to typical man-pages sections.

  • name (only if there is a system present at all)

  • synopsis

  • description (only if the system has a long-description)

  • commands

  • environment variables

  • authors (only if the system has at least one author or maintainer)

  • reporting bugs (only if there is a command named "bugs" or if the system has a bug-tracker)

  • copyright (only if there is a command named "copyright" or if the system has a license)

  • see also (only if the system has a homepage)

You can remove those sections by setting the help-section for them to NIL, or add your own via define-help-section:

(command-line:define-help-section files (stream)
  :order 40
  (command-line:with-help-section (stream ".my-rc" 2)
    (f "Read when the program starts up to initialise the environment before anything else.")))

By default any help output will automatically be line wrapped and indented nicely to follow the correct layout. The with-help-section macro also helps to indent inner sections properly.

Sometimes you may only want to show a help section depending on some runtime test. To do this, you can provide a :test body option, the form of which will be evaluated first to decide whether to print the section at all.

System Information

1.0.0
Yukari Hafner
zlib

Definition Index