From 8ca07fc6c658b17b5eee0c5582fe7a94d89bc0cb Mon Sep 17 00:00:00 2001 From: Momchil Ivanov Date: Fri, 8 Feb 2019 21:07:25 +0100 Subject: [PATCH 01/20] Fix a bug: the parser signals unknown-option for --option when there is another longer option of the form --option-long. --- unix-opts.lisp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/unix-opts.lisp b/unix-opts.lisp index d557698..ce9e86b 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -254,10 +254,13 @@ the program as first elements of the list. Portable across implementations." (let ((x (string x))) (when (>= (length x) (length opt)) (string= x opt :end1 (length opt)))))) - (let ((matches (remove-if-not #'prefix-p *options* :key key))) - (if (cadr matches) - nil - (car matches)))))) + (let* ((matches (remove-if-not #'prefix-p *options* :key key)) + (exact-match (find-if #'(lambda (x) (string= x opt)) + matches :key key))) + (cond + (exact-match exact-match) + ((cadr matches) nil) + (otherwise (car matches))))))) (defun get-opts (&optional options) "Parse command line options. If OPTIONS is given, it should be a list to From 6e4afde9952a4c2badfebd3407d91e3341b1a4c8 Mon Sep 17 00:00:00 2001 From: Momchil Ivanov Date: Mon, 11 Feb 2019 05:19:16 +0100 Subject: [PATCH 02/20] replace otherwise with t --- unix-opts.lisp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix-opts.lisp b/unix-opts.lisp index ce9e86b..63144fa 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -260,7 +260,7 @@ the program as first elements of the list. Portable across implementations." (cond (exact-match exact-match) ((cadr matches) nil) - (otherwise (car matches))))))) + (t (car matches))))))) (defun get-opts (&optional options) "Parse command line options. If OPTIONS is given, it should be a list to From 767ab3dd15c51869d25ab81a2e4712d34ce91880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Almeida?= Date: Wed, 8 Jan 2020 14:19:59 +0000 Subject: [PATCH 03/20] Fix command line argument retrieval for Allegro CL In Allegro CL, the symbol `sys:command-line-arguments' is a function and must be called in order to correctly access command line arguments. --- unix-opts.lisp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix-opts.lisp b/unix-opts.lisp index d557698..c02b271 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -191,7 +191,7 @@ printed in option description." "Return a list of program's arguments, including command used to execute the program as first elements of the list. Portable across implementations." #+abcl ext:*command-line-argument-list* - #+allegro sys:command-line-arguments + #+allegro (sys:command-line-arguments) #+:ccl ccl:*command-line-argument-list* #+clisp (cons *load-truename* ext:*args*) #+clozure ccl:*command-line-argument-list* From 6c72ab98eddc35f16fd9a9f9356cd546d0cbafa3 Mon Sep 17 00:00:00 2001 From: cage Date: Sun, 19 Apr 2020 18:18:15 +0200 Subject: [PATCH 04/20] - changed alignment of options in descriptions. --- unix-opts.lisp | 60 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/unix-opts.lisp b/unix-opts.lisp index d557698..2de3317 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -394,37 +394,57 @@ to `nil')" prefixed with PADDING spaces. If NEWLINE is non-NIL, newline character will be prepended to the text making it start on the next line with padding applied to every single line." - (let ((pad (make-string padding :initial-element #\Space))) + (let ((pad (make-string padding :initial-element #\Space)) + (pad-next-lines (make-string (max 0 (1- padding)) :initial-element #\Space))) (with-output-to-string (s) (when newline - (format s "~&~a" pad)) + (format s "~%~a" pad)) (map nil (lambda (x) (write-char x s) (when (char= x #\Newline) - (write pad :stream s :escape nil))) + (write pad-next-lines :stream s :escape nil))) str)))) (defun print-opts (&optional (stream *standard-output*)) "Print info about defined options to STREAM. Every option get its own line with description." - (dolist (opt *options*) - (with-slots (short long description required arg-parser meta-var) opt - (let ((opts-and-meta - (concatenate - 'string - (if short (format nil "-~c" short) "") - (if (and short long) ", " "") - (if long (format nil "--~a" long) "") - (if arg-parser (format nil " ~a" meta-var) "") - (if required (format nil " (Required)") "")))) - (format stream " ~25a~a~%" - opts-and-meta - (add-text-padding - description - :padding 27 - :newline (>= (length opts-and-meta) 25)))))) - (terpri stream)) + (flet ((pad-right (string max-size) + (concatenate 'string + string + (make-string (- max-size + (length string)) + :initial-element #\Space)))) + (let ((max-opts-length -1) + (all-opts-meta ()) + (all-opts-descriptions ())) + (dolist (opt *options*) + (with-slots (short long description required arg-parser meta-var) opt + (let ((opts-and-meta + (concatenate + 'string + (if short (format nil "-~c" short) "") + (if (and short long) ", " "") + (if long (format nil "--~a" long) "") + (if arg-parser (format nil " ~a" meta-var) "") + (if required (format nil " (Required)") "")))) + (push opts-and-meta all-opts-meta) + (push description all-opts-descriptions) + (when (> (length opts-and-meta) + max-opts-length) + (setf max-opts-length + (length opts-and-meta)))))) + (setf max-opts-length (+ 1 max-opts-length)) + (loop + for opt-meta in all-opts-meta + for opt-description in all-opts-descriptions do + (format stream " ~a~a~%" + (pad-right opt-meta max-opts-length) + (add-text-padding opt-description + :padding (+ 2 max-opts-length) + :newline (>= (length opt-meta) + 25)))) + (terpri stream)))) (defun print-opts* (margin) "Return a string containing info about defined options. All options are From 9041fb8dba76eae9ac9d42b733a432a3412e73c9 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sun, 3 May 2020 11:00:14 +0530 Subject: [PATCH 05/20] travis should check for ecl --- .gitignore | 1 + .travis.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d0f1392..323c1b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.fas *.fasl *~ +*.o \#* diff --git a/.travis.yml b/.travis.yml index a95f942..0f7c754 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: - LISP=ccl32 - LISP=clisp - LISP=clisp32 + - LISP=ecl install: - if [ -x ./install.sh ] && head -2 ./install.sh | grep '^# cl-travis' > /dev/null; From b570f44db7689cff5b5853562888198bc11e0d5b Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sun, 3 May 2020 11:07:40 +0530 Subject: [PATCH 06/20] travis change from luismbo/cl-travis to sionescu/cl-travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0f7c754..b63e9ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ install: then ./install.sh; else - curl https://raw.githubusercontent.com/luismbo/cl-travis/master/install.sh | sh; + curl https://raw.githubusercontent.com/sionescu/cl-travis/master/install.sh | sh; fi before_script: From 114452cdb318c3c87a65619959742465063078a9 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sun, 3 May 2020 11:24:57 +0530 Subject: [PATCH 07/20] travis added lib(32)stdc++-7-dev from ubuntu-toolchain-r-test Reference: https://stackoverflow.com/questions/52674349/c17-code-not-compiling-on-travis-with-clang-6-0 Travis uses Ubuntu 14.04 which does not have libstdc++-7-* --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index b63e9ec..708d049 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,13 @@ language: lisp sudo: required +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - libstdc++-7-dev + - lib32stdc++-7-dev env: matrix: - LISP=abcl From 1841db856cacd99155136024766c5e3cb23ecf55 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sun, 3 May 2020 12:34:51 +0530 Subject: [PATCH 08/20] travis allow failure for ccl32 Issue filed at: https://github.com/Clozure/ccl/issues/304 --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 708d049..cfc8a40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,10 @@ env: - LISP=clisp32 - LISP=ecl +matrix: + allow_failures: + - env: LISP=ccl32 # issue filed at https://github.com/Clozure/ccl/issues/304 + install: - if [ -x ./install.sh ] && head -2 ./install.sh | grep '^# cl-travis' > /dev/null; then From 9f6ae6e7b3f6f6faa32112c2d58cc7c747ba24e6 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Fri, 22 May 2020 21:50:01 +0530 Subject: [PATCH 09/20] travis: build status image link update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f7f7a3..7f6ec28 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Unix-style command line options parser [![License MIT](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) -[![Build Status](https://travis-ci.org/mrkkrp/unix-opts.svg?branch=master)](https://travis-ci.org/mrkkrp/unix-opts) +[![Build Status](https://travis-ci.org/mrkkrp/unix-opts.svg?branch=master)](https://travis-ci.com/digikar99/unix-opts.svg?branch=master) [![Quicklisp](http://quickdocs.org/badge/unix-opts.svg)](http://quickdocs.org/unix-opts/) This is a minimalistic parser of command line options. The main advantage of From 1de2e52ab8ca46b232b79583152ceea2ddd36d9f Mon Sep 17 00:00:00 2001 From: digikar99 Date: Fri, 22 May 2020 23:49:14 +0530 Subject: [PATCH 10/20] using fiveam for testing; added a failing test failing test refers to https://github.com/libre-man/unix-opts/issues/22 --- .travis.yml | 3 +- tests.lisp | 208 +++++++++++++++++++++++++++----------------- unix-opts-tests.asd | 32 ------- unix-opts.asd | 12 ++- 4 files changed, 138 insertions(+), 117 deletions(-) delete mode 100644 unix-opts-tests.asd diff --git a/.travis.yml b/.travis.yml index a95f942..e95ab64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,8 +23,7 @@ before_script: - echo "(defsystem :dummy-cl-travis-system)" > ~/lisp/dummy-cl-travis-system.asd script: - - cl -e '(asdf:load-system :unix-opts-tests) - (unix-opts:run-tests)' + - cl -e '(asdf:test-system :unix-opts)' [ $? -eq 1 ] notifications: diff --git a/tests.lisp b/tests.lisp index 5809858..7cc15a9 100644 --- a/tests.lisp +++ b/tests.lisp @@ -23,28 +23,36 @@ ;;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ;;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -(in-package #:unix-opts) +(defpackage :unix-opts/tests + (:shadowing-import-from :cl :describe) + (:use :cl :fiveam :unix-opts) + (:local-nicknames (:opts :unix-opts))) -(define-opts +(in-package :unix-opts/tests) + +(def-suite :unix-opts) +(in-suite :unix-opts) + +(opts:define-opts (:name :grab-int - :description "grab integer INT" - :short #\i - :long "grab-int" - :required t - :arg-parser #'parse-integer - :meta-var "INT") + :description "grab integer INT" + :short #\i + :long "grab-int" + :required t + :arg-parser #'parse-integer + :meta-var "INT") (:name :grab-str - :description "grab string STR" - :short #\s - :long "grab-str" - :arg-parser #'identity - :meta-var "STR") + :description "grab string STR" + :short #\s + :long "grab-str" + :arg-parser #'identity + :meta-var "STR") (:name :flag-a - :description "flag with short form only" - :short #\a) + :description "flag with short form only" + :short #\a) (:name :flag-b - :description "flag with long form only" - :long "flag-b")) + :description "flag with long form only" + :long "flag-b")) ;;; Here is some variables that we will use and functions to reset them. @@ -85,117 +93,153 @@ recommended to supply them all if you don't want to end in the debugger." (multiple-value-prog1 (handler-bind ((unknown-option - (lambda (c) - (push (option c) *unknown-options*) - (when unknown-option - (apply #'invoke-restart unknown-option)))) + (lambda (c) + (push (option c) *unknown-options*) + (when unknown-option + (apply #'invoke-restart unknown-option)))) (missing-arg - (lambda (c) - (push (option c) *missing-arg-options*) - (when missing-arg - (apply #'invoke-restart missing-arg)))) + (lambda (c) + (push (option c) *missing-arg-options*) + (when missing-arg + (apply #'invoke-restart missing-arg)))) (missing-required-option - (lambda (c) - (push (mapcar #'name (missing-options c)) *missing-required-options*) - (when missing-required - (apply #'invoke-restart missing-required)))) + (lambda (c) + ;; TODO: Should we export unix-opts::name? + (push (mapcar #'unix-opts::name (missing-options c)) *missing-required-options*) + (when missing-required + (apply #'invoke-restart missing-required)))) (arg-parser-failed - (lambda (c) - (push (raw-arg c) *malformed-arguments*) - (when arg-parser-failed - (apply #'invoke-restart arg-parser-failed))))) + (lambda (c) + (push (raw-arg c) *malformed-arguments*) + (when arg-parser-failed + (apply #'invoke-restart arg-parser-failed))))) (get-opts opts)) (finish-collecting))) -(defun run-tests () - "Run Unix-opts tests. Signal failure if any test fails and return NIL -otherwise." - (assert (typep (argv) 'list)) +(def-test argv () + (is (typep (opts:argv) 'list))) + +(def-test unexpected-options () + (is (typep (handler-case (opts:get-opts '("--grab-int" "10" "--rere")) + (condition (c) c)) + 'unknown-option)) + (is (typep (handler-case (opts:get-opts '()) + (condition (c) c)) + 'missing-required-option)) + (is (typep (handler-case (opts:get-opts '("--grab-int" "hello")) + (condition (c) c)) + 'arg-parser-failed)) + (is (typep (handler-case (opts:get-opts '("--grab-int")) + (condition (c) c)) + 'missing-arg)) + ;; At one point of time, we were comparing prefixes due to which the + ;; following used to parse correctly + (is (typep (handler-case (opts:get-opts '("--grab-int" "10" "--grab-s" "hello")) + (condition (c) c)) + 'unknown-option)) + ;; TODO: Should we error in the following case? + (is (typep (handler-case (opts:get-opts '("--grab-int" "10" "-a" "11")) + (condition (c) c)) + 'list))) +(def-test miscelleneous-1 () (multiple-value-bind (options free-args) (parse-opts '("--grab-int" "10" "--rere" "11" "-s" "-a" "foo.txt") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-int 10 :flag-a t))) - (assert (equalp free-args '("11" "foo.txt"))) - (assert (equalp *unknown-options* '("--rere"))) - (assert (equalp *missing-arg-options* '("-s"))) - (assert (equalp *malformed-arguments* nil))) + (is (equalp options '(:grab-int 10 :flag-a t))) + (is (equalp free-args '("11" "foo.txt"))) + (is (equalp *unknown-options* '("--rere"))) + (is (equalp *missing-arg-options* '("-s"))) + (is (equalp *malformed-arguments* nil)))) + +(def-test miscelleneous-2 () (multiple-value-bind (options free-args) (parse-opts '("-asri=13" "--flag-b" "--flag-b" "foo.txt" "bar.txt") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:flag-a t :grab-int 13 :flag-b t :flag-b t))) - (assert (equalp free-args '("foo.txt" "bar.txt"))) - (assert (equalp *unknown-options* '("-r"))) - (assert (equalp *missing-arg-options* '("-s"))) - (assert (equalp *malformed-arguments* nil))) + (is (equalp options '(:flag-a t :grab-int 13 :flag-b t :flag-b t))) + (is (equalp free-args '("foo.txt" "bar.txt"))) + (is (equalp *unknown-options* '("-r"))) + (is (equalp *missing-arg-options* '("-s"))) + (is (equalp *malformed-arguments* nil)))) + +(def-test miscelleneous-3 () (multiple-value-bind (options free-args) (parse-opts '("--grab-str=fooba" "-i" "what" "-i" "100" "--roro" "-") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-str "fooba" :grab-int 100))) - (assert (equalp free-args '("-"))) - (assert (equalp *unknown-options* '("--roro"))) - (assert (equalp *missing-arg-options* nil)) - (assert (equalp *malformed-arguments* '("what")))) + (is (equalp options '(:grab-str "fooba" :grab-int 100))) + (is (equalp free-args '("-"))) + (is (equalp *unknown-options* '("--roro"))) + (is (equalp *missing-arg-options* nil)) + (is (equalp *malformed-arguments* '("what"))))) + +(def-test miscelleneous-3 () (multiple-value-bind (options free-args) (parse-opts '("--foobar" "cat" "-sl") ; very tricky (see restarts) :unknown-option '(use-value "--grab-int") :missing-arg '(use-value "my-string") :arg-parser-failed '(reparse-arg "15")) - (assert (equalp options '(:grab-int 15 :grab-str "my-string" - :grab-int "my-string"))) - (assert (equalp free-args nil)) - (assert (equalp *unknown-options* '("--foobar" "-l"))) - (assert (equalp *missing-arg-options* '("-s" "--grab-int"))) - (assert (equalp *malformed-arguments* '("cat")))) + (is (equalp options '(:grab-int 15 :grab-str "my-string" + :grab-int "my-string"))) + (is (equalp free-args nil)) + (is (equalp *unknown-options* '("--foobar" "-l"))) + (is (equalp *missing-arg-options* '("-s" "--grab-int"))) + (is (equalp *malformed-arguments* '("cat"))))) + +(def-test miscelleneous-4 () (multiple-value-bind (options free-args) (parse-opts '("--grab-i" "10" "--grab" "14" "--grab-s") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-int 10))) - (assert (equalp free-args '("14"))) - (assert (equalp *unknown-options* '("--grab"))) - (assert (equalp *missing-arg-options* '("--grab-s"))) - (assert (equalp *malformed-arguments* nil))) + (is (equalp options '(:grab-int 10))) + (is (equalp free-args '("14"))) + (is (equalp *unknown-options* '("--grab"))) + (is (equalp *missing-arg-options* '("--grab-s"))) + (is (equalp *malformed-arguments* nil)))) + +(def-test miscelleneous-5 () (multiple-value-bind (options free-args) (parse-opts '("--grab-int" "15" "--" "--grab-int" "16") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-int 15))) - (assert (equalp free-args '("--grab-int" "16"))) - (assert (equalp *unknown-options* nil)) - (assert (equalp *missing-arg-options* nil)) - (assert (equalp *malformed-arguments* nil))) + (is (equalp options '(:grab-int 15))) + (is (equalp free-args '("--grab-int" "16"))) + (is (equalp *unknown-options* nil)) + (is (equalp *missing-arg-options* nil)) + (is (equalp *malformed-arguments* nil)))) + +(def-test miscelleneous-6 () (multiple-value-bind (options free-args) (parse-opts '("-s" "5") :unknown-option '(skip-option) :missing-arg '(skip-option) :missing-required '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-str "5"))) - (assert (equalp free-args '())) - (assert (equalp *missing-required-options* '((:grab-int)))) - (assert (equalp *unknown-options* nil)) - (assert (equalp *missing-arg-options* nil)) - (assert (equalp *malformed-arguments* nil))) + (is (equalp options '(:grab-str "5"))) + (is (equalp free-args '())) + (is (equalp *missing-required-options* '((:grab-int)))) + (is (equalp *unknown-options* nil)) + (is (equalp *missing-arg-options* nil)) + (is (equalp *malformed-arguments* nil)))) + +(def-test miscelleneous-7 () (multiple-value-bind (options free-args) (parse-opts '("-s" "5") :unknown-option '(skip-option) :missing-arg '(skip-option) :missing-required '(use-value (15)) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-str "5" :grab-int 15))) - (assert (equalp free-args '())) - (assert (equalp *missing-required-options* '((:grab-int)))) - (assert (equalp *unknown-options* nil)) - (assert (equalp *missing-arg-options* nil)) - (assert (equalp *malformed-arguments* nil)))) - -(export 'run-tests) + (is (equalp options '(:grab-str "5" :grab-int 15))) + (is (equalp free-args '())) + (is (equalp *missing-required-options* '((:grab-int)))) + (is (equalp *unknown-options* nil)) + (is (equalp *missing-arg-options* nil)) + (is (equalp *malformed-arguments* nil)))) + diff --git a/unix-opts-tests.asd b/unix-opts-tests.asd deleted file mode 100644 index d96d67e..0000000 --- a/unix-opts-tests.asd +++ /dev/null @@ -1,32 +0,0 @@ -;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp -*- -;;; -;;; ASDF system definition for unix-opts-tests -;;; -;;; Copyright © 2015–2018 Mark Karpov -;;; -;;; Permission is hereby granted, free of charge, to any person obtaining a -;;; copy of this software and associated documentation files (the -;;; "Software"), to deal in the Software without restriction, including -;;; without limitation the rights to use, copy, modify, merge, publish, -;;; distribute, sublicense, and/or sell copies of the Software, and to -;;; permit persons to whom the Software is furnished to do so, subject to -;;; the following conditions: -;;; -;;; The above copyright notice and this permission notice shall be included -;;; in all copies or substantial portions of the Software. -;;; -;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -;;; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -;;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -;;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -;;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -(asdf:defsystem :unix-opts-tests - :version "0.1.7" - :description "tests for unix-opts-tests" - :author "Mark Karpov" - :license "MIT" - :components ((:file "tests")) - :depends-on (:unix-opts)) diff --git a/unix-opts.asd b/unix-opts.asd index 83910ac..1872525 100644 --- a/unix-opts.asd +++ b/unix-opts.asd @@ -29,4 +29,14 @@ :description "minimalistic parser of command line arguments" :author "Mark Karpov" :license "MIT" - :components ((:file "unix-opts"))) + :components ((:file "unix-opts")) + :in-order-to ((asdf:test-op (load-op "unix-opts/tests"))) + :perform (asdf:test-op (o c) (uiop:symbol-call "FIVEAM" "RUN" :unix-opts))) + +(asdf:defsystem "unix-opts/tests" + :version "0.1.7" + :description "tests for unix-opts" + :author "Mark Karpov" + :license "MIT" + :components ((:file "tests")) + :depends-on ("fiveam" "unix-opts")) From 7e7a6f02648984108367c0b23890e304755b2fa5 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 00:01:34 +0530 Subject: [PATCH 11/20] travis: disable all except sbcl; load using quicklisp --- .travis.yml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index e95ab64..46762b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,22 @@ language: lisp sudo: required +git: + depth: 2 + env: matrix: - - LISP=abcl +# - LISP=abcl - LISP=sbcl - LISP=sbcl32 - - LISP=ccl - - LISP=ccl32 - - LISP=clisp - - LISP=clisp32 +# - LISP=ccl +# - LISP=ccl32 +# - LISP=clisp +# - LISP=clisp32 install: - - if [ -x ./install.sh ] && head -2 ./install.sh | grep '^# cl-travis' > /dev/null; + - # installing cl-travis + if [ -x ./install.sh ] && head -2 ./install.sh | grep '^# cl-travis' > /dev/null; then ./install.sh; else @@ -23,7 +27,8 @@ before_script: - echo "(defsystem :dummy-cl-travis-system)" > ~/lisp/dummy-cl-travis-system.asd script: - - cl -e '(asdf:test-system :unix-opts)' + - cl -e '(ql:quickload :unix-opts/tests) + (asdf:test-system :unix-opts)' [ $? -eq 1 ] notifications: From b18121c4d33389188d81fc93c514ec178a65d886 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 00:08:11 +0530 Subject: [PATCH 12/20] fiveam: set debug-on-failure debug-on-error to t --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 46762b1..f33e50a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,8 @@ before_script: script: - cl -e '(ql:quickload :unix-opts/tests) + (setq 5am:*debug-on-failure* t) + (setq 5am:*debug-on-error* t) (asdf:test-system :unix-opts)' [ $? -eq 1 ] From 16ba2ef24b0f3387de213af17d5db956cfa682e7 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 00:48:54 +0530 Subject: [PATCH 13/20] removed failing case: ls --alm works --- tests.lisp | 17 ++++++----------- unix-opts.lisp | 3 +++ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tests.lisp b/tests.lisp index 7cc15a9..166552b 100644 --- a/tests.lisp +++ b/tests.lisp @@ -132,11 +132,6 @@ recommended to supply them all if you don't want to end in the debugger." (is (typep (handler-case (opts:get-opts '("--grab-int")) (condition (c) c)) 'missing-arg)) - ;; At one point of time, we were comparing prefixes due to which the - ;; following used to parse correctly - (is (typep (handler-case (opts:get-opts '("--grab-int" "10" "--grab-s" "hello")) - (condition (c) c)) - 'unknown-option)) ;; TODO: Should we error in the following case? (is (typep (handler-case (opts:get-opts '("--grab-int" "10" "-a" "11")) (condition (c) c)) @@ -178,7 +173,7 @@ recommended to supply them all if you don't want to end in the debugger." (is (equalp *missing-arg-options* nil)) (is (equalp *malformed-arguments* '("what"))))) -(def-test miscelleneous-3 () +(def-test miscelleneous-4 () (multiple-value-bind (options free-args) (parse-opts '("--foobar" "cat" "-sl") ; very tricky (see restarts) :unknown-option '(use-value "--grab-int") @@ -191,9 +186,9 @@ recommended to supply them all if you don't want to end in the debugger." (is (equalp *missing-arg-options* '("-s" "--grab-int"))) (is (equalp *malformed-arguments* '("cat"))))) -(def-test miscelleneous-4 () +(def-test miscelleneous-5 () (multiple-value-bind (options free-args) - (parse-opts '("--grab-i" "10" "--grab" "14" "--grab-s") + (parse-opts '("--grab-int" "10" "--grab" "14" "--grab-s") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) @@ -203,7 +198,7 @@ recommended to supply them all if you don't want to end in the debugger." (is (equalp *missing-arg-options* '("--grab-s"))) (is (equalp *malformed-arguments* nil)))) -(def-test miscelleneous-5 () +(def-test miscelleneous-6 () (multiple-value-bind (options free-args) (parse-opts '("--grab-int" "15" "--" "--grab-int" "16") :unknown-option '(skip-option) @@ -215,7 +210,7 @@ recommended to supply them all if you don't want to end in the debugger." (is (equalp *missing-arg-options* nil)) (is (equalp *malformed-arguments* nil)))) -(def-test miscelleneous-6 () +(def-test miscelleneous-7 () (multiple-value-bind (options free-args) (parse-opts '("-s" "5") :unknown-option '(skip-option) @@ -229,7 +224,7 @@ recommended to supply them all if you don't want to end in the debugger." (is (equalp *missing-arg-options* nil)) (is (equalp *malformed-arguments* nil)))) -(def-test miscelleneous-7 () +(def-test miscelleneous-8 () (multiple-value-bind (options free-args) (parse-opts '("-s" "5") :unknown-option '(skip-option) diff --git a/unix-opts.lisp b/unix-opts.lisp index d557698..0d07de1 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -254,7 +254,10 @@ the program as first elements of the list. Portable across implementations." (let ((x (string x))) (when (>= (length x) (length opt)) (string= x opt :end1 (length opt)))))) + ;; Yes we use prefix, because `ls --al`, `ls --all`, `ls --alm`. (let ((matches (remove-if-not #'prefix-p *options* :key key))) + ;; Return "the" match if unique + ;; TODO: Should we raise ambiguous option error (if (cadr matches) nil (car matches)))))) From be82a2677a9a21249692677371f4ac2f7406271d Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 02:39:38 +0530 Subject: [PATCH 14/20] added expand-opts https://github.com/libre-man/unix-opts/issues/19 --- tests.lisp | 18 ++++++++++++++++++ unix-opts.lisp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/tests.lisp b/tests.lisp index 9ab9df2..824c6b4 100644 --- a/tests.lisp +++ b/tests.lisp @@ -246,3 +246,21 @@ recommended to supply them all if you don't want to end in the debugger." (is (equalp *missing-arg-options* nil)) (is (equalp *malformed-arguments* nil)))) +(def-test expand-opts () + (is (equalp + (macroexpand-1 + '(opts:expand-opts + (:help "Show this help text.") + (:port "Port number on which to run the server." #'parse-integer t) + (:swank-port "Port number at which to start swank [default: 8080]" #'parse-integer) + (:debug "Run in debug mode if specified" #'identity))) + '(UNIX-OPTS:DEFINE-OPTS + (:NAME :HELP :DESCRIPTION "Show this help text." :SHORT #\h :REQUIRED NIL + :LONG "help" :ARG-PARSER NIL) + (:NAME :PORT :DESCRIPTION "Port number on which to run the server." :SHORT + #\p :REQUIRED T :LONG "port" :ARG-PARSER #'PARSE-INTEGER) + (:NAME :SWANK-PORT :DESCRIPTION + "Port number at which to start swank [default: 8080]" :SHORT #\s :REQUIRED + NIL :LONG "swank-port" :ARG-PARSER #'PARSE-INTEGER) + (:NAME :DEBUG :DESCRIPTION "Run in debug mode if specified" :SHORT #\d + :REQUIRED NIL :LONG "debug" :ARG-PARSER #'IDENTITY))))) diff --git a/unix-opts.lisp b/unix-opts.lisp index d0b0de2..3122377 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -39,6 +39,7 @@ #:exit #:raw-arg #:define-opts + #:expand-opts #:argv #:get-opts #:describe) @@ -196,6 +197,40 @@ printed in option description." (setf *options* (nreverse *options*)) (values))) +(defmacro expand-opts (&body descriptions) + "Each description should be of the format + (name-as-keyword description &optional parser required short). +So that something as short as the following gets the work done. + (expand-opts + (:help \"Show this help text.\") + (:port \"Port number on which to run the server.\" #'parse-integer t) + (:swank-port \"Port number at which to start swank [default: 8080]\" #'parse-integer) + (:debug \"Run in debug mode if specified\" #'identity))" + `(opts:define-opts + ,@(let* ((used-short-names (make-hash-table)) + (get-unique-short-name + (lambda (name) + (loop for ch across name + do (when (and (not (gethash ch used-short-names)) + (alpha-char-p ch)) + (setf (gethash ch used-short-names) t) + (return ch)) + finally + (error "Could not find a unique short name for ~D" name))))) + (loop for description in descriptions + collect + (destructuring-bind (name description &optional + parser required short) + description + (let ((name-string (string-downcase (symbol-name name)))) + `(:name ,name + :description ,description + :short ,(or short (funcall get-unique-short-name + name-string)) + :required ,required + :long ,name-string + :arg-parser ,parser))))))) + (defun argv () "Return a list of program's arguments, including command used to execute the program as first elements of the list. Portable across implementations." From 8f5ea05446ade16368845cbdaef8caadaec37afa Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 02:55:37 +0530 Subject: [PATCH 15/20] unused fiveam and local-nicknames: some impl still do not support --- .travis.yml | 2 - tests.lisp | 191 ++++++++++++++++++++++++++------------------------ unix-opts.asd | 4 +- 3 files changed, 103 insertions(+), 94 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1f5c332..a165530 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,8 +39,6 @@ before_script: script: - cl -e '(ql:quickload :unix-opts/tests) - (setq 5am:*debug-on-failure* t) - (setq 5am:*debug-on-error* t) (asdf:test-system :unix-opts)' [ $? -eq 1 ] diff --git a/tests.lisp b/tests.lisp index 824c6b4..1ae7628 100644 --- a/tests.lisp +++ b/tests.lisp @@ -25,14 +25,10 @@ (defpackage :unix-opts/tests (:shadowing-import-from :cl :describe) - (:use :cl :fiveam :unix-opts) - (:local-nicknames (:opts :unix-opts))) + (:use :cl :unix-opts)) (in-package :unix-opts/tests) -(def-suite :unix-opts) -(in-suite :unix-opts) - (opts:define-opts (:name :grab-int :description "grab integer INT" @@ -123,144 +119,159 @@ recommended to supply them all if you don't want to end in the debugger." (get-opts opts)) (finish-collecting))) -(def-test argv () - (is (typep (opts:argv) 'list))) +(defun argv-test () + (assert (typep (opts:argv) 'list))) -(def-test unexpected-options () - (is (typep (handler-case (opts:get-opts '("--grab-int" "10" "--rere")) - (condition (c) c)) - 'unknown-option)) - (is (typep (handler-case (opts:get-opts '()) - (condition (c) c)) - 'missing-required-option)) - (is (typep (handler-case (opts:get-opts '("--grab-int" "hello")) - (condition (c) c)) - 'arg-parser-failed)) - (is (typep (handler-case (opts:get-opts '("--grab-int")) - (condition (c) c)) - 'missing-arg)) +(defun unexpected-options-test () + (assert (typep (handler-case (opts:get-opts '("--grab-int" "10" "--rere")) + (condition (c) c)) + 'unknown-option)) + (assert (typep (handler-case (opts:get-opts '()) + (condition (c) c)) + 'missing-required-option)) + (assert (typep (handler-case (opts:get-opts '("--grab-int" "hello")) + (condition (c) c)) + 'arg-parser-failed)) + (assert (typep (handler-case (opts:get-opts '("--grab-int")) + (condition (c) c)) + 'missing-arg)) ;; TODO: Should we error in the following case? - (is (typep (handler-case (opts:get-opts '("--grab-int" "10" "-a" "11")) - (condition (c) c)) - 'list))) + (assert (typep (handler-case (opts:get-opts '("--grab-int" "10" "-a" "11")) + (condition (c) c)) + 'list))) -(def-test miscelleneous-1 () +(defun miscelleneous-1 () (multiple-value-bind (options free-args) (parse-opts '("--grab-int" "10" "--rere" "11" "-s" "-a" "foo.txt") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (is (equalp options '(:grab-int 10 :flag-a t))) - (is (equalp free-args '("11" "foo.txt"))) - (is (equalp *unknown-options* '("--rere"))) - (is (equalp *missing-arg-options* '("-s"))) - (is (equalp *malformed-arguments* nil)))) + (assert (equalp options '(:grab-int 10 :flag-a t))) + (assert (equalp free-args '("11" "foo.txt"))) + (assert (equalp *unknown-options* '("--rere"))) + (assert (equalp *missing-arg-options* '("-s"))) + (assert (equalp *malformed-arguments* nil)))) -(def-test miscelleneous-2 () +(defun miscelleneous-2 () (multiple-value-bind (options free-args) (parse-opts '("-asri=13" "--flag-b" "--flag-b" "foo.txt" "bar.txt") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (is (equalp options '(:flag-a t :grab-int 13 :flag-b t :flag-b t))) - (is (equalp free-args '("foo.txt" "bar.txt"))) - (is (equalp *unknown-options* '("-r"))) - (is (equalp *missing-arg-options* '("-s"))) - (is (equalp *malformed-arguments* nil)))) + (assert (equalp options '(:flag-a t :grab-int 13 :flag-b t :flag-b t))) + (assert (equalp free-args '("foo.txt" "bar.txt"))) + (assert (equalp *unknown-options* '("-r"))) + (assert (equalp *missing-arg-options* '("-s"))) + (assert (equalp *malformed-arguments* nil)))) -(def-test miscelleneous-3 () +(defun miscelleneous-3 () (multiple-value-bind (options free-args) (parse-opts '("--grab-str=fooba" "-i" "what" "-i" "100" "--roro" "-") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (is (equalp options '(:grab-str "fooba" :grab-int 100))) - (is (equalp free-args '("-"))) - (is (equalp *unknown-options* '("--roro"))) - (is (equalp *missing-arg-options* nil)) - (is (equalp *malformed-arguments* '("what"))))) + (assert (equalp options '(:grab-str "fooba" :grab-int 100))) + (assert (equalp free-args '("-"))) + (assert (equalp *unknown-options* '("--roro"))) + (assert (equalp *missing-arg-options* nil)) + (assert (equalp *malformed-arguments* '("what"))))) -(def-test miscelleneous-4 () +(defun miscelleneous-4 () (multiple-value-bind (options free-args) (parse-opts '("--foobar" "cat" "-sl") ; very tricky (see restarts) :unknown-option '(use-value "--grab-int") :missing-arg '(use-value "my-string") :arg-parser-failed '(reparse-arg "15")) - (is (equalp options '(:grab-int 15 :grab-str "my-string" + (assert (equalp options '(:grab-int 15 :grab-str "my-string" :grab-int "my-string"))) - (is (equalp free-args nil)) - (is (equalp *unknown-options* '("--foobar" "-l"))) - (is (equalp *missing-arg-options* '("-s" "--grab-int"))) - (is (equalp *malformed-arguments* '("cat"))))) + (assert (equalp free-args nil)) + (assert (equalp *unknown-options* '("--foobar" "-l"))) + (assert (equalp *missing-arg-options* '("-s" "--grab-int"))) + (assert (equalp *malformed-arguments* '("cat"))))) -(def-test miscelleneous-5 () +(defun miscelleneous-5 () (multiple-value-bind (options free-args) (parse-opts '("--grab-int" "10" "--grab" "14" "--grab-s") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option) :ambiguous-option '(skip-option)) - (is (equalp options '(:grab-int 10))) - (is (equalp free-args '("14"))) - (is (null (set-difference *ambiguous-options* '("--grab" "--grab-s") + (assert (equalp options '(:grab-int 10))) + (assert (equalp free-args '("14"))) + (assert (null (set-difference *ambiguous-options* '("--grab" "--grab-s") :test #'equal))) - (is (equalp *malformed-arguments* nil)))) + (assert (equalp *malformed-arguments* nil)))) -(def-test miscelleneous-6 () +(defun miscelleneous-6 () (multiple-value-bind (options free-args) (parse-opts '("--grab-int" "15" "--" "--grab-int" "16") :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (is (equalp options '(:grab-int 15))) - (is (equalp free-args '("--grab-int" "16"))) - (is (equalp *unknown-options* nil)) - (is (equalp *missing-arg-options* nil)) - (is (equalp *malformed-arguments* nil)))) + (assert (equalp options '(:grab-int 15))) + (assert (equalp free-args '("--grab-int" "16"))) + (assert (equalp *unknown-options* nil)) + (assert (equalp *missing-arg-options* nil)) + (assert (equalp *malformed-arguments* nil)))) -(def-test miscelleneous-7 () +(defun miscelleneous-7 () (multiple-value-bind (options free-args) (parse-opts '("-s" "5") :unknown-option '(skip-option) :missing-arg '(skip-option) :missing-required '(skip-option) :arg-parser-failed '(skip-option)) - (is (equalp options '(:grab-str "5"))) - (is (equalp free-args '())) - (is (equalp *missing-required-options* '((:grab-int)))) - (is (equalp *unknown-options* nil)) - (is (equalp *missing-arg-options* nil)) - (is (equalp *malformed-arguments* nil)))) + (assert (equalp options '(:grab-str "5"))) + (assert (equalp free-args '())) + (assert (equalp *missing-required-options* '((:grab-int)))) + (assert (equalp *unknown-options* nil)) + (assert (equalp *missing-arg-options* nil)) + (assert (equalp *malformed-arguments* nil)))) -(def-test miscelleneous-8 () +(defun miscelleneous-8 () (multiple-value-bind (options free-args) (parse-opts '("-s" "5") :unknown-option '(skip-option) :missing-arg '(skip-option) :missing-required '(use-value (15)) :arg-parser-failed '(skip-option)) - (is (equalp options '(:grab-str "5" :grab-int 15))) - (is (equalp free-args '())) - (is (equalp *missing-required-options* '((:grab-int)))) - (is (equalp *unknown-options* nil)) - (is (equalp *missing-arg-options* nil)) - (is (equalp *malformed-arguments* nil)))) + (assert (equalp options '(:grab-str "5" :grab-int 15))) + (assert (equalp free-args '())) + (assert (equalp *missing-required-options* '((:grab-int)))) + (assert (equalp *unknown-options* nil)) + (assert (equalp *missing-arg-options* nil)) + (assert (equalp *malformed-arguments* nil)))) + +(defun expand-opts-test () + (assert (equalp + (macroexpand-1 + '(opts:expand-opts + (:help "Show this help text.") + (:port "Port number on which to run the server." #'parse-integer t) + (:swank-port "Port number at which to start swank [default: 8080]" #'parse-integer) + (:debug "Run in debug mode if specified" #'identity))) + '(UNIX-OPTS:DEFINE-OPTS + (:NAME :HELP :DESCRIPTION "Show this help text." :SHORT #\h :REQUIRED NIL + :LONG "help" :ARG-PARSER NIL) + (:NAME :PORT :DESCRIPTION "Port number on which to run the server." :SHORT + #\p :REQUIRED T :LONG "port" :ARG-PARSER #'PARSE-INTEGER) + (:NAME :SWANK-PORT :DESCRIPTION + "Port number at which to start swank [default: 8080]" :SHORT #\s :REQUIRED + NIL :LONG "swank-port" :ARG-PARSER #'PARSE-INTEGER) + (:NAME :DEBUG :DESCRIPTION "Run in debug mode if specified" :SHORT #\d + :REQUIRED NIL :LONG "debug" :ARG-PARSER #'IDENTITY))))) -(def-test expand-opts () - (is (equalp - (macroexpand-1 - '(opts:expand-opts - (:help "Show this help text.") - (:port "Port number on which to run the server." #'parse-integer t) - (:swank-port "Port number at which to start swank [default: 8080]" #'parse-integer) - (:debug "Run in debug mode if specified" #'identity))) - '(UNIX-OPTS:DEFINE-OPTS - (:NAME :HELP :DESCRIPTION "Show this help text." :SHORT #\h :REQUIRED NIL - :LONG "help" :ARG-PARSER NIL) - (:NAME :PORT :DESCRIPTION "Port number on which to run the server." :SHORT - #\p :REQUIRED T :LONG "port" :ARG-PARSER #'PARSE-INTEGER) - (:NAME :SWANK-PORT :DESCRIPTION - "Port number at which to start swank [default: 8080]" :SHORT #\s :REQUIRED - NIL :LONG "swank-port" :ARG-PARSER #'PARSE-INTEGER) - (:NAME :DEBUG :DESCRIPTION "Run in debug mode if specified" :SHORT #\d - :REQUIRED NIL :LONG "debug" :ARG-PARSER #'IDENTITY))))) +(defun run () + (dolist (fn '(argv-test unexpected-options-test + miscelleneous-1 + miscelleneous-2 + miscelleneous-3 + miscelleneous-4 + miscelleneous-5 + miscelleneous-6 + miscelleneous-7 + miscelleneous-8 + expand-opts-test)) + (funcall fn) + (format t "~D ran successfully~%" fn)) + (format t "All tests ran successfully!")) diff --git a/unix-opts.asd b/unix-opts.asd index 1872525..ca80143 100644 --- a/unix-opts.asd +++ b/unix-opts.asd @@ -31,7 +31,7 @@ :license "MIT" :components ((:file "unix-opts")) :in-order-to ((asdf:test-op (load-op "unix-opts/tests"))) - :perform (asdf:test-op (o c) (uiop:symbol-call "FIVEAM" "RUN" :unix-opts))) + :perform (asdf:test-op (o c) (uiop:symbol-call "UNIX-OPTS/TESTS" "RUN"))) (asdf:defsystem "unix-opts/tests" :version "0.1.7" @@ -39,4 +39,4 @@ :author "Mark Karpov" :license "MIT" :components ((:file "tests")) - :depends-on ("fiveam" "unix-opts")) + :depends-on ("unix-opts")) From 2bc4d18e0067cc5db61b0fd8cc9e0f8a97561328 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 03:09:36 +0530 Subject: [PATCH 16/20] unused in-order-to and perform and uiop --- .travis.yml | 5 +++-- tests.lisp | 3 ++- unix-opts.asd | 7 +++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index a165530..351d3cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,8 +38,9 @@ before_script: - echo "(defsystem :dummy-cl-travis-system)" > ~/lisp/dummy-cl-travis-system.asd script: - - cl -e '(ql:quickload :unix-opts/tests) - (asdf:test-system :unix-opts)' + - cl -e '(ql:quickload :unix-opts) + (ql:quickload :unix-opts/tests) + (unix-opts/tests:run)' [ $? -eq 1 ] notifications: diff --git a/tests.lisp b/tests.lisp index 1ae7628..c7ac45d 100644 --- a/tests.lisp +++ b/tests.lisp @@ -25,7 +25,8 @@ (defpackage :unix-opts/tests (:shadowing-import-from :cl :describe) - (:use :cl :unix-opts)) + (:use :cl :unix-opts) + (:export :run)) (in-package :unix-opts/tests) diff --git a/unix-opts.asd b/unix-opts.asd index ca80143..95ce4eb 100644 --- a/unix-opts.asd +++ b/unix-opts.asd @@ -24,14 +24,13 @@ ;;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ;;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -(asdf:defsystem :unix-opts +(asdf:defsystem "unix-opts" :version "0.1.7" :description "minimalistic parser of command line arguments" :author "Mark Karpov" :license "MIT" - :components ((:file "unix-opts")) - :in-order-to ((asdf:test-op (load-op "unix-opts/tests"))) - :perform (asdf:test-op (o c) (uiop:symbol-call "UNIX-OPTS/TESTS" "RUN"))) + ;; clisp doesn't seem to support in-order-to and uiop and such, nor fiveam + :components ((:file "unix-opts"))) (asdf:defsystem "unix-opts/tests" :version "0.1.7" From ca3f3d3f043aecd00c162aab220e8f6aaca0a049 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 11:00:57 +0530 Subject: [PATCH 17/20] get-opts uses options if option-supplied-p --- .travis.yml | 3 --- unix-opts.lisp | 18 ++++++++---------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 351d3cd..dcd7df8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,9 +34,6 @@ install: curl https://raw.githubusercontent.com/sionescu/cl-travis/master/install.sh | sh; fi -before_script: - - echo "(defsystem :dummy-cl-travis-system)" > ~/lisp/dummy-cl-travis-system.asd - script: - cl -e '(ql:quickload :unix-opts) (ql:quickload :unix-opts/tests) diff --git a/unix-opts.lisp b/unix-opts.lisp index 3122377..12ae6a4 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -307,7 +307,7 @@ the program as first elements of the list. Portable across implementations." ((cadr matches) matches) (t (car matches))))))) -(defun get-opts (&optional options) +(defun get-opts (&optional (options nil options-supplied-p)) "Parse command line options. If OPTIONS is given, it should be a list to parse. If it's not given, the function will use `argv' function to get list of command line arguments. @@ -349,7 +349,9 @@ be used), `skip-option' (ignore all these options, effectively binding them to `nil')" (do ((tokens (mapcan #'split-short-opts (mapcan #'split-on-= - (or options (cdr (argv))))) + (if options-supplied-p + options + (cdr (argv))))) (cdr tokens)) (required (loop :with table = (make-hash-table) :for option :in *options* @@ -423,19 +425,15 @@ to `nil')" (process-arg item)) (poption-name (restart-case - (error 'missing-arg - :option poption-raw) + (error 'missing-arg :option poption-raw) (use-value (value) (push-option poption-name value) - (when item - (process-option item))) + (when item (process-option item))) (skip-option () (setf poption-name nil) - (when item - (process-option item))))) + (when item (process-option item))))) ((string= item "--") - (dolist (tok (cdr tokens)) - (push tok free-args)) + (dolist (tok (cdr tokens)) (push tok free-args)) (setf tokens nil)) ((optionp item) (process-option item)) From 7f52367bb0617eeacac378abcb08184c50d75fc9 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 11:40:45 +0530 Subject: [PATCH 18/20] added default https://github.com/libre-man/unix-opts/issues/17 --- tests.lisp | 29 +++++++++++++++++++---------- unix-opts.lisp | 21 ++++++++++++++++++--- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/tests.lisp b/tests.lisp index c7ac45d..cd8c015 100644 --- a/tests.lisp +++ b/tests.lisp @@ -48,7 +48,8 @@ :description "option to cause ambiguity with grab-str as well as help test the print function of opts:describe due to this long description" :short #\s :long "grab-string" - :arg-parser #'identity) + :arg-parser #'identity + :default 42) (:name :flag-a :description "flag with short form only" :short #\a) @@ -147,7 +148,8 @@ recommended to supply them all if you don't want to end in the debugger." :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-int 10 :flag-a t))) + (assert (equalp options '(:grab-int 10 :flag-a t + :grab-string 42))) (assert (equalp free-args '("11" "foo.txt"))) (assert (equalp *unknown-options* '("--rere"))) (assert (equalp *missing-arg-options* '("-s"))) @@ -159,7 +161,8 @@ recommended to supply them all if you don't want to end in the debugger." :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:flag-a t :grab-int 13 :flag-b t :flag-b t))) + (assert (equalp options '(:flag-a t :grab-int 13 :flag-b t :flag-b t + :grab-string 42))) (assert (equalp free-args '("foo.txt" "bar.txt"))) (assert (equalp *unknown-options* '("-r"))) (assert (equalp *missing-arg-options* '("-s"))) @@ -171,7 +174,8 @@ recommended to supply them all if you don't want to end in the debugger." :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-str "fooba" :grab-int 100))) + (assert (equalp options '(:grab-str "fooba" :grab-int 100 + :grab-string 42))) (assert (equalp free-args '("-"))) (assert (equalp *unknown-options* '("--roro"))) (assert (equalp *missing-arg-options* nil)) @@ -184,7 +188,8 @@ recommended to supply them all if you don't want to end in the debugger." :missing-arg '(use-value "my-string") :arg-parser-failed '(reparse-arg "15")) (assert (equalp options '(:grab-int 15 :grab-str "my-string" - :grab-int "my-string"))) + :grab-int "my-string" ; TODO: should this be the behaviour + :grab-string 42))) (assert (equalp free-args nil)) (assert (equalp *unknown-options* '("--foobar" "-l"))) (assert (equalp *missing-arg-options* '("-s" "--grab-int"))) @@ -197,10 +202,11 @@ recommended to supply them all if you don't want to end in the debugger." :missing-arg '(skip-option) :arg-parser-failed '(skip-option) :ambiguous-option '(skip-option)) - (assert (equalp options '(:grab-int 10))) + (assert (equalp options '(:grab-int 10 + :grab-string 42))) (assert (equalp free-args '("14"))) (assert (null (set-difference *ambiguous-options* '("--grab" "--grab-s") - :test #'equal))) + :test #'equal))) (assert (equalp *malformed-arguments* nil)))) (defun miscelleneous-6 () @@ -209,7 +215,8 @@ recommended to supply them all if you don't want to end in the debugger." :unknown-option '(skip-option) :missing-arg '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-int 15))) + (assert (equalp options '(:grab-int 15 + :grab-string 42))) (assert (equalp free-args '("--grab-int" "16"))) (assert (equalp *unknown-options* nil)) (assert (equalp *missing-arg-options* nil)) @@ -222,7 +229,8 @@ recommended to supply them all if you don't want to end in the debugger." :missing-arg '(skip-option) :missing-required '(skip-option) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-str "5"))) + (assert (equalp options '(:grab-str "5" + :grab-string 42))) (assert (equalp free-args '())) (assert (equalp *missing-required-options* '((:grab-int)))) (assert (equalp *unknown-options* nil)) @@ -236,7 +244,8 @@ recommended to supply them all if you don't want to end in the debugger." :missing-arg '(skip-option) :missing-required '(use-value (15)) :arg-parser-failed '(skip-option)) - (assert (equalp options '(:grab-str "5" :grab-int 15))) + (assert (equalp options '(:grab-str "5" :grab-int 15 + :grab-string 42))) (assert (equalp free-args '())) (assert (equalp *missing-required-options* '((:grab-int)))) (assert (equalp *unknown-options* nil)) diff --git a/unix-opts.lisp b/unix-opts.lisp index 12ae6a4..6833055 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -79,7 +79,13 @@ parsed with this function") :initarg :meta-var :accessor meta-var :documentation "if this option requires an argument, this is how it will -be printed in option description")) +be printed in option description") + (default + :initarg :default + :initform nil + :accessor default + :documentation "if this option requires an argument, this is the value that will be +used if the option is not supplied")) (:documentation "representation of an option")) (define-condition troublesome-option (simple-error) @@ -149,7 +155,8 @@ an argument, it's given but cannot be parsed by argument parser.")) (long (getf args :long)) (arg-parser (getf args :arg-parser)) (required (getf args :required)) - (meta-var (getf args :meta-var "ARG"))) + (meta-var (getf args :meta-var "ARG")) + (default (getf args :default nil))) (unless (or short long) (error "at least one form of the option must be provided")) (check-type name keyword) @@ -166,7 +173,8 @@ an argument, it's given but cannot be parsed by argument parser.")) :long long :required required :arg-parser arg-parser - :meta-var meta-var) + :meta-var meta-var + :default default) *options*))) (defmacro define-opts (&body descriptions) @@ -378,6 +386,13 @@ to `nil')" :for value :in values :do (push (name option) options) :do (push value options)))))) + ;; handle default options + (loop :for option :in *options* + :for name = (name option) + :when (and (default option) + (null (getf options name))) + :do (push name options) + (push (default option) options)) (values (nreverse options) (nreverse free-args)))) (labels ((push-option (name value) From 5cfb260037370723f09c7b02a45cc1a91defecc0 Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 11:49:13 +0530 Subject: [PATCH 19/20] exported troublesome-option https://github.com/libre-man/unix-opts/issues/13 --- unix-opts.lisp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unix-opts.lisp b/unix-opts.lisp index 6833055..6f84f25 100644 --- a/unix-opts.lisp +++ b/unix-opts.lisp @@ -26,7 +26,8 @@ (defpackage :unix-opts (:nicknames :opts) (:use #:common-lisp) - (:export #:unknown-option + (:export #:troublesome-option + #:unknown-option #:ambiguous-option #:missing-arg #:arg-parser-failed From e7e382055166d4521f414822eaf8fddd94bff21e Mon Sep 17 00:00:00 2001 From: digikar99 Date: Sat, 23 May 2020 12:15:39 +0530 Subject: [PATCH 20/20] readme build status --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f6ec28..8f01967 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Unix-style command line options parser [![License MIT](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) -[![Build Status](https://travis-ci.org/mrkkrp/unix-opts.svg?branch=master)](https://travis-ci.com/digikar99/unix-opts.svg?branch=master) +[![Build Status](https://travis-ci.org/digikar99/unix-opts.svg?branch=master)](https://travis-ci.com/digikar99/unix-opts.svg?branch=master) [![Quicklisp](http://quickdocs.org/badge/unix-opts.svg)](http://quickdocs.org/unix-opts/) This is a minimalistic parser of command line options. The main advantage of