diff --git a/Makefile.am b/Makefile.am index c7562c5..09a0d6d 100755 --- a/Makefile.am +++ b/Makefile.am @@ -47,7 +47,9 @@ pkgmoduledir = $(guilesitedir)/$(PACKAGE) pkgmodule_DATA = src/mcron/config.scm dist_pkgmodule_DATA = \ src/mcron/base.scm \ + src/mcron/command-line-processor.scm \ src/mcron/environment.scm \ + src/mcron/getopt-long.scm \ src/mcron/job-specifier.scm \ src/mcron/redirect.scm \ src/mcron/utils.scm \ diff --git a/src/cron.in b/src/cron.in index b260a5e..4fb65c8 100644 --- a/src/cron.in +++ b/src/cron.in @@ -28,7 +28,7 @@ (use-modules (mcron scripts cron) (mcron utils) - (ice-9 command-line-processor)) + (mcron command-line-processor)) (process-command-line (command-line) application "cron" @@ -49,5 +49,4 @@ copyright "2003 - 2022 Free Software Foundation, Inc." license GPLv3) - (catch-mcron-error (main --schedule --noetc)) diff --git a/src/crontab.in b/src/crontab.in index f203a98..fb624a3 100644 --- a/src/crontab.in +++ b/src/crontab.in @@ -27,7 +27,7 @@ (set! %load-compiled-path (cons "%modbuilddir%" %load-compiled-path))) (use-modules (mcron scripts crontab) - (ice-9 command-line-processor)) + (mcron command-line-processor)) (process-command-line (command-line) application "crontab" diff --git a/src/mcron.in b/src/mcron.in index a7707e0..ac4aace 100644 --- a/src/mcron.in +++ b/src/mcron.in @@ -28,7 +28,7 @@ (use-modules (mcron scripts mcron) (mcron utils) - (ice-9 command-line-processor)) + (mcron command-line-processor)) (process-command-line (command-line) application "mcron" diff --git a/src/mcron/command-line-processor.scm b/src/mcron/command-line-processor.scm new file mode 100644 index 0000000..5b5491b --- /dev/null +++ b/src/mcron/command-line-processor.scm @@ -0,0 +1,653 @@ +;;;; -*- scheme -*- +;;;; command-line-processor.scm --- command-line options processing +;;;; +;;;; Copyright (C) 1998, 2001, 2006, 2009, 2011, 2020 +;;;; Free Software Foundation, Inc. +;;;; +;;;; This library is free software; you can redistribute it and/or +;;;; modify it under the terms of the GNU Lesser General Public +;;;; License as published by the Free Software Foundation; either +;;;; version 3 of the License, or (at your option) any later version. +;;;; +;;;; This library is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;;; Lesser General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU Lesser General Public +;;;; License along with this library; if not, write to the Free Software +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +;;;; 02110-1301 USA + +;;; Author: Dale Mellor May, 2020 + +;;; Commentary: + +;;; Where the Guile (ice-9 getopt-long) module, modelled after the GNU C +;;; libraryʼs ‘getopt_long’ function, allows an application to construct +;;; a grammar prescribing the decomposition of the command-line options, +;;; this module, inspired by the C libraryʼs ‘argp’ parser, gives the +;;; application a higher-level paradigm in which the command-line +;;; processing is specified declaratively. This includes enough of the +;;; application meta-data and some fragmentary help strings for the +;;; completely automatic generation of responses to GNU-standard +;;; ‘--help’, ‘--version’ and ‘--usage’ options, thus alleviating the +;;; need of the application itself to deal with these things. +;;; +;;; The module has three specific aims. +;;; +;;; 1) Provide higher-level declarative interface, easier to use. +;;; +;;; 2) Automatically respond to --help, --version and --usage +;;; options. +;;; +;;; 3) Allow amalgamation of specifications, so that an application +;;; can mix in requirements from modules into its own option +;;; specification--THIS IS NOT CURRENTLY IMPLEMENTED. +;;; +;;; There is just one function which needs to be called to get all of +;;; this functionality: it is ‘process-command-line’, and has the side +;;; effect that new variable bindings appear in the current module +;;; corresponding to all the options. For example, if a declared option +;;; is ‘--do-this’, then a variable called, literally, ‘--do-this’ will +;;; be injected in the current namespace and will have the value +;;; provided on the command-line, or simply #t or #f to indicate whether +;;; or not that option was present on the command line. +;;; +;;; Alternatively, it is possible to create and compose the +;;; specification in separate steps, and then call the above method with +;;; the results. The functions ‘command-line-specification’ and +;;; ‘merge-command-line-specifications’ are provided to this end. + +;;; (process-command-line COMMAND-LINE SPECIFICATION) +;;; Process the COMMAND-LINE according to the application SPECIFICATION. +;;; +;;; COMMAND-LINE is a list of strings, such as that returned from the +;;; core ‘command-line’ function. +;;; +;;; SPECIFICATION is a form holding a space-separated mix of selection +;;; words followed by their respective declarations. The selection +;;; words are ‘application’, ‘author’, ‘bug-address’, ‘copyright’, +;;; ‘help-preamble’, ‘help-postamble’, ‘license’, ‘option’, ‘usage’ and +;;; ‘version’, and can appear in any order. +;;; +;;; ‘application’ should be followed by a string: the name of the +;;; application with possibly the package name in +;;; parentheses afterwards +;;; ‘author’ should be followed by a string giving the name of one of +;;; the packageʼs authors. This selection word can be +;;; repeated as many times as necessary to provide the names +;;; of all authors. +;;; ‘bug-address’ should be followed by a string giving the URL of a +;;; contact-point for sending bug reports, such as an +;;; e-mail address or web address of bug-tracking system +;;; interface +;;; ‘copyright’ should be followed by a string containing a list of +;;; years and an entity to whom the copyright is assigned. +;;; This may be repeated to list other assignees +;;; ‘help-preamble’ should be followed by a number of strings which +;;; make up a short paragraph of text displayed before +;;; a full list of the available program options +;;; ‘help-postamble’, like the preamble, is followed by strings which +;;; make up a paragraph of text, shown after the list +;;; of options +;;; ‘license’ can be followed by one of the words ‘GPLv3’ [this is +;;; currently the only standard choice implemented], or else +;;; a string which briefly gives out the terms of the license +;;; ‘option’ is followed by an option declaration, described below +;;; ‘usage’ is followed by a string describing the usage of the +;;; application on one line +;;; ‘version’ is followed by a string providing the current version +;;; number of this program +;;; +;;; The ‘option’ declaration is followed by another form bracketed by +;;; parentheses and holding a space-separated mix of declarations (order +;;; irrelevant). +;;; +;;; A word beginning with two hyphens, an optional exclamation point, +;;; alpha-numeric characters, an optional equals sign, and an +;;; optional further word. There must be exactly one of these, and +;;; they determine the long name of the option. An exclamation point +;;; indicates that the option MUST appear on the command line, an +;;; equals indicates that the option MUST have a value unless it is +;;; followed in the specification by a value, in which case the value +;;; on the command-line is optional and the one in the specification +;;; will be taken as the default when not given on the command line. +;;; +;;; A word comprised of one hyphen and one letter or number. There +;;; can be exactly zero or one of these, and it declares that the +;;; option has this short form available on the command-line. As a +;;; very special exception: if you want to use ‘-i’ as an option, it +;;; must be specified with the identifier ‘short-i’ (a naked /-i/ is +;;; read as a complex number); ditto ‘short-I’ for ‘-I’. +;;; +;;; A number of strings which are catenated together to provide a +;;; short, succinct description of the option. These strings should +;;; be approximately half the width of a page, i.e. about 40 +;;; characters. +;;; +;;; A function which will be used as a predicate to decide if a value +;;; is allowable for this option. There should be zero or one of +;;; these. +;;; +;;; For the precise presentation of options on the command-line, the +;;; reader should refer to the description of the ‘getopt-long’ module, +;;; which underlies the present one. +;;; +;;; At this point a short example is in order. The main entry point for +;;; the GNU Mcron program has as its first clause +;;; +;;; (process-command-line (command-line) +;;; application "mcron" +;;; version "1.4" +;;; usage "[OPTIONS]... [FILES]..." +;;; help-preamble +;;; "Run an mcron process according to the specifications in the FILE... " +;;; "(`-' for standard input), or use all the files in ~/.config/cron " +;;; "(or the deprecated ~/.cron) with .guile or .vixie extensions.\n" +;;; "Note that --daemon and --schedule are mutually exclusive." +;;; option (--daemon -d +;;; "run as a daemon process") +;;; option (--stdin=guile short-i (λ (in) (or (string=? in "guile") +;;; (string=? in "vixie"))) +;;; "format of data passed as standard input or file " +;;; "arguments, 'guile' or 'vixie' (default guile)") +;;; option (--schedule=8 -s string->number +;;; "display the next N (or 8) jobs that will be run") +;;; help-postamble +;;; "Mandatory or optional arguments to long options are also mandatory or " +;;; "optional for any corresponding short options." +;;; bug-address "bug-mcron@gnu.org" +;;; copyright "2003, 2006, 2014, 2020 Free Software Foundation, Inc." +;;; license GPLv3) +;;; +;;; after which there are four new variable bindings in the present +;;; namespace: --daemon, --stdin, --schedule and --! (the latter holds +;;; all the command-line arguments that did not partake in option +;;; processing) whose values depend on the specific command-line options +;;; the end user furnished. + +;;; (command-line-specification SPECIFICATION) +;;; Compiles an object which encapsulates the given SPECIFICATION. +;;; +;;; For details of how to give a SPECIFICATION, see the description of +;;; the full ‘process-command-line’ function above. The return from +;;; this method can be used in the partial version of +;;; ‘process-command-line’ described below, and in the following +;;; ‘merge-command-line-specifications’ function. + +;;; (merge-command-line-specifications SPECIFICATION_OBJECT ...) Make a +;;; single specification object which embodies the amalgamation of all +;;; of the specification objects given as arguments. +;;; +;;; Order is important: if two option items specify the same short form +;;; for the option (a single letter), then only the first option will +;;; actually have that short form available at the command-line. +;;; Similarly, if two options have exactly the same name, the second (or +;;; later) ones will have a numerical digit appended to their name. + +;;; (process-command-line COMMAND-LINE SPECIFICATION-OBJECT) Perform +;;; exactly the same function as the full ‘process-command-line’ +;;; function described above, but takes a pre-made specification object +;;; produced using the two functions above. + +;;; Bugs/To do +;;; +;;; 1) This stuff currently only works in the top-level module. +;;; +;;; 2) Want to be able to amalgamate command-line specifications from +;;; different modules. Will need to get to the bottom of the first +;;; issue before we can tackle this one (somehow need to put the +;;; --option variable bindings into the right places, or at least +;;; replicate them all in all modules which want to do some processing +;;; of the command line). +;;; +;;; 3) Want more license boilerplate text; currently we only have GPLv3. + +;;; Code: + +(define-module (mcron command-line-processor) + #:use-module (srfi srfi-1) ;; fold + #:use-module (srfi srfi-9) ;; records + #:use-module (srfi srfi-9 gnu) ;; set/get-fields + #:use-module (mcron getopt-long) + #:use-module (ice-9 regex) + #:export (specific option item + obtain-getopt-long-results + process-getopt-long-results + + ;; These are the real public exports. + process-command-line + command-line-specification + merge-command-line-specifications)) + + + +(define-record-type <> + (make-specification- preamble postamble copyright authors options) + specification? + (name spec:name spec:set-name!) + (version spec:version spec:set-version!) + (usage spec:usage spec:set-usage!) + (preamble spec:preamble spec:set-preamble!) + (postamble spec:postamble spec:set-postamble!) + (bug-address spec:bugs spec:set-bugs!) + (copyright spec:copyright spec:set-copyright!) + (license spec:license spec:set-license!) + (authors spec:authors spec:set-authors!) + (options spec:options spec:set-all-options!)) + +;; We initialize the fields which are supposed to be lists, but +;; generally this procedure should *not* be considered to be producing a +;; properly specified <> record. +(define (make-specification) (make-specification- '() '() '() '() '())) + + + +(define-record-type <