aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Kamat2018-05-08 12:36:36 -0700
committerNoam Postavsky2018-05-15 19:32:49 -0400
commita4c616e27aa48e7d524e0c5cfaf67f17d04989e4 (patch)
tree67ac930677e194e8ab3d583568c191c28294d996
parent92a8230e49a65be48442ee95cf50c90514e48f99 (diff)
downloademacs-a4c616e27aa48e7d524e0c5cfaf67f17d04989e4.tar.gz
emacs-a4c616e27aa48e7d524e0c5cfaf67f17d04989e4.zip
esh-opt.el: Add a :parse-leading-options-only argument (Bug#28323)
* lisp/eshell/esh-opt.el (eshell-eval-using-options): Add a new :parse-leading-options-only argument which ignores dash/switch arguments after the first positional argument. (eshell--process-args): Abort processing of arguments if we see one positional argument and :parse-leading-options-only is set. * lisp/eshell/em-tramp.el (eshell/sudo): Use :parse-leading-options-only, to avoid parsing subcommand switches as switches of sudo itself. * test/lisp/eshell/esh-opt-tests.el: Add tests for new and old behavior.
-rw-r--r--lisp/eshell/em-tramp.el1
-rw-r--r--lisp/eshell/esh-opt.el17
-rw-r--r--test/lisp/eshell/esh-opt-tests.el124
3 files changed, 139 insertions, 3 deletions
diff --git a/lisp/eshell/em-tramp.el b/lisp/eshell/em-tramp.el
index 004c4954908..9475f4ed949 100644
--- a/lisp/eshell/em-tramp.el
+++ b/lisp/eshell/em-tramp.el
@@ -107,6 +107,7 @@ Uses the system sudo through TRAMP's sudo method."
107 '((?h "help" nil nil "show this usage screen") 107 '((?h "help" nil nil "show this usage screen")
108 (?u "user" t user "execute a command as another USER") 108 (?u "user" t user "execute a command as another USER")
109 :show-usage 109 :show-usage
110 :parse-leading-options-only
110 :usage "[(-u | --user) USER] COMMAND 111 :usage "[(-u | --user) USER] COMMAND
111Execute a COMMAND as the superuser or another USER.") 112Execute a COMMAND as the superuser or another USER.")
112 (throw 'eshell-external 113 (throw 'eshell-external
diff --git a/lisp/eshell/esh-opt.el b/lisp/eshell/esh-opt.el
index 67b7d05985d..80eb15359a2 100644
--- a/lisp/eshell/esh-opt.el
+++ b/lisp/eshell/esh-opt.el
@@ -80,6 +80,10 @@ arguments, some do not. The recognized :KEYWORDS are:
80 If present, do not pass MACRO-ARGS through `eshell-flatten-list' 80 If present, do not pass MACRO-ARGS through `eshell-flatten-list'
81and `eshell-stringify-list'. 81and `eshell-stringify-list'.
82 82
83:parse-leading-options-only
84 If present, do not parse dash or switch arguments after the first
85positional argument. Instead, treat them as positional arguments themselves.
86
83For example, OPTIONS might look like: 87For example, OPTIONS might look like:
84 88
85 ((?C nil nil multi-column \"multi-column display\") 89 ((?C nil nil multi-column \"multi-column display\")
@@ -245,12 +249,19 @@ switch is unrecognized."
245 (list sym))))) 249 (list sym)))))
246 options))) 250 options)))
247 (ai 0) arg 251 (ai 0) arg
248 (eshell--args args)) 252 (eshell--args args)
249 (while (< ai (length eshell--args)) 253 (pos-argument-found nil))
254 (while (and (< ai (length eshell--args))
255 ;; Abort if we saw the first pos argument and option is set
256 (not (and pos-argument-found
257 (memq :parse-leading-options-only options))))
250 (setq arg (nth ai eshell--args)) 258 (setq arg (nth ai eshell--args))
251 (if (not (and (stringp arg) 259 (if (not (and (stringp arg)
252 (string-match "^-\\(-\\)?\\(.*\\)" arg))) 260 (string-match "^-\\(-\\)?\\(.*\\)" arg)))
253 (setq ai (1+ ai)) 261 ;; Positional argument found, skip
262 (setq ai (1+ ai)
263 pos-argument-found t)
264 ;; dash or switch argument found, parse
254 (let* ((dash (match-string 1 arg)) 265 (let* ((dash (match-string 1 arg))
255 (switch (match-string 2 arg))) 266 (switch (match-string 2 arg)))
256 (if (= ai 0) 267 (if (= ai 0)
diff --git a/test/lisp/eshell/esh-opt-tests.el b/test/lisp/eshell/esh-opt-tests.el
new file mode 100644
index 00000000000..13b522b389e
--- /dev/null
+++ b/test/lisp/eshell/esh-opt-tests.el
@@ -0,0 +1,124 @@
1;;; tests/esh-opt-tests.el --- esh-opt test suite
2
3;; Copyright (C) 2018 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software: you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation, either version 3 of the License, or
10;; (at your option) any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
19
20;;; Code:
21
22(require 'ert)
23(require 'esh-opt)
24
25(ert-deftest esh-opt-process-args-test ()
26 "Unit tests which verify correct behavior of `eshell--process-args'."
27 (should
28 (equal '(t)
29 (eshell--process-args
30 "sudo"
31 '("-a")
32 '((?a "all" nil show-all "")))))
33 (should
34 (equal '(nil)
35 (eshell--process-args
36 "sudo"
37 '("-g")
38 '((?a "all" nil show-all "")))))
39 (should
40 (equal '("root" "world")
41 (eshell--process-args
42 "sudo"
43 '("-u" "root" "world")
44 '((?u "user" t user "execute a command as another USER")))))
45 (should
46 (equal '(nil "emerge" "-uDN" "world")
47 (eshell--process-args
48 "sudo"
49 '("emerge" "-uDN" "world")
50 '((?u "user" t user "execute a command as another USER")
51 :parse-leading-options-only))))
52 (should
53 (equal '("root" "emerge" "-uDN" "world")
54 (eshell--process-args
55 "sudo"
56 '("-u" "root" "emerge" "-uDN" "world")
57 '((?u "user" t user "execute a command as another USER")
58 :parse-leading-options-only))))
59 (should
60 (equal '("world" "emerge")
61 (eshell--process-args
62 "sudo"
63 '("-u" "root" "emerge" "-uDN" "world")
64 '((?u "user" t user "execute a command as another USER"))))))
65
66(ert-deftest test-eshell-eval-using-options ()
67 "Tests for `eshell-eval-using-options'."
68 (eshell-eval-using-options
69 "sudo" '("-u" "root" "whoami")
70 '((?u "user" t user "execute a command as another USER")
71 :parse-leading-options-only)
72 (should (equal user "root")))
73 (eshell-eval-using-options
74 "sudo" '("--user" "root" "whoami")
75 '((?u "user" t user "execute a command as another USER")
76 :parse-leading-options-only)
77 (should (equal user "root")))
78
79 (eshell-eval-using-options
80 "sudo" '("emerge" "-uDN" "world")
81 '((?u "user" t user "execute a command as another USER"))
82 (should (equal user "world")))
83 (eshell-eval-using-options
84 "sudo" '("emerge" "-uDN" "world")
85 '((?u "user" t user "execute a command as another USER")
86 :parse-leading-options-only)
87 (should (eq user nil)))
88
89 (eshell-eval-using-options
90 "ls" '("-I" "*.txt" "/dev/null")
91 '((?I "ignore" t ignore-pattern
92 "do not list implied entries matching pattern"))
93 (should (equal ignore-pattern "*.txt")))
94
95 (eshell-eval-using-options
96 "ls" '("-l" "/dev/null")
97 '((?l nil long-listing listing-style
98 "use a long listing format"))
99 (should (eql listing-style 'long-listing)))
100 (eshell-eval-using-options
101 "ls" '("/dev/null")
102 '((?l nil long-listing listing-style
103 "use a long listing format"))
104 (should (eq listing-style nil)))
105
106 (eshell-eval-using-options
107 "ls" '("/dev/null" "-h")
108 '((?h "human-readable" 1024 human-readable
109 "print sizes in human readable format"))
110 (should (eql human-readable 1024)))
111 (eshell-eval-using-options
112 "ls" '("/dev/null" "--human-readable")
113 '((?h "human-readable" 1024 human-readable
114 "print sizes in human readable format"))
115 (should (eql human-readable 1024)))
116 (eshell-eval-using-options
117 "ls" '("/dev/null")
118 '((?h "human-readable" 1024 human-readable
119 "print sizes in human readable format"))
120 (should (eq human-readable nil))))
121
122(provide 'esh-opt-tests)
123
124;;; esh-opt-tests.el ends here