]> git.eshelyaron.com Git - emacs.git/commitdiff
Add the "doas" alias to eshell.
authorBrian Cully <bjc@kublai.com>
Thu, 27 Oct 2022 01:10:21 +0000 (21:10 -0400)
committerJim Porter <jporterbugs@gmail.com>
Sat, 5 Nov 2022 19:05:05 +0000 (12:05 -0700)
  * lisp/eshell/em-tramp.el (eshell/doas): new function.
  (eshell--method-wrap-directory): new function.
  (eshell/sudo): accept '-s'/'--shell' for interactive use.
  * test/lisp/eshell/em-tramp-tests.el
  (em-tramp-test/sudo-shell) (em-tramp-test/sudo-user-shell)
  (em-tramp-test/doas-basic) (em-tramp-test/doas-user)
  (em-tramp-test/doas-shell) (em-tramp-test/doas-user-shell): new
  tests.
  * etc/NEWS: mention new 'doas' eshell command.
  * doc/misc/eshell.texi: add 'doas' command documentation.

doc/misc/eshell.texi
etc/NEWS
lisp/eshell/em-tramp.el
test/lisp/eshell/em-tramp-tests.el

index ff368c9dc4118d3f254ebb7a26383a324c283fa8..96873a3f9a558f14e6cfef2035606f075ca99670 100644 (file)
@@ -717,9 +717,12 @@ current environment.
 @cmindex su
 @itemx sudo
 @cmindex sudo
-Uses TRAMP's @command{su} or @command{sudo} method @pxref{Inline methods, , , tramp}
-to run a command via @command{su} or @command{sudo}.  These commands
-are in the eshell-tramp module, which is disabled by default.
+@itemx doas
+@cmindex doas
+Uses TRAMP's @command{su}, @command{sudo}, or @command{doas} method
+@pxref{Inline methods, , , tramp} to run a command via @command{su},
+@command{sudo}, or @command{doas}.  These commands are in the
+eshell-tramp module, which is disabled by default.
 
 
 @item substitute
index df755c6ed12a14ca49b499ffd8e0e00198808fc4..89da8aa63f7817229558baf756ee390cdc689165 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -370,6 +370,11 @@ node in the Eshell manual for more details.
 *** Eshell pipelines now only pipe stdout by default.
 To pipe both stdout and stderr, use the '|&' operator instead of '|'.
 
+*** New eshell built-in command 'doas'.
+The privilege-escalation program 'doas' has been added to the existing
+'su' and 'sudo' commands from the 'eshell-tramp' module.  The external
+command may still be accessed by using '*doas'.
+
 ---
 ** The 'delete-forward-char' command now deletes by grapheme clusters.
 This command is by default bound to the <Delete> function key
index aebbc36e71dc4e4743ef1f29c25c263181fc8cbb..3daac1db3b491dd1bfc63216b96ca706f3067fc4 100644 (file)
  (defgroup eshell-tramp nil
    "This module defines commands that use TRAMP in a way that is
   not transparent to the user.  So far, this includes only the
-  built-in su and sudo commands, which are not compatible with
-  the full, external su and sudo commands, and require the user
-  to understand how to use the TRAMP sudo method."
+  built-in su, sudo and doas commands, which are not compatible
+  with the full, external su, sudo, and doas commands, and
+  require the user to understand how to use the TRAMP sudo
+  method."
    :tag "TRAMP Eshell features"
    :group 'eshell-module))
 
@@ -52,7 +53,7 @@
     (add-hook 'pcomplete-try-first-hook
              'eshell-complete-host-reference nil t))
   (setq-local eshell-complex-commands
-              (append '("su" "sudo")
+              (append '("su" "sudo" "doas")
                       eshell-complex-commands)))
 
 (autoload 'eshell-parse-command "esh-cmd")
@@ -91,6 +92,21 @@ Become another USER during a login session.")
 
 (put 'eshell/su 'eshell-no-numeric-conversions t)
 
+(defun eshell--method-wrap-directory (directory method &optional user)
+  "Return DIRECTORY as accessed by a Tramp METHOD for USER."
+  (let ((user (or user "root"))
+        (dir (file-local-name (expand-file-name directory)))
+        (prefix (file-remote-p directory))
+        (host (or (file-remote-p directory 'host)
+                 tramp-default-host))
+        (rmethod (file-remote-p directory 'method))
+        (ruser (file-remote-p directory 'user)))
+    (if (and prefix (or (not (string-equal rmethod method))
+                     (not (string-equal ruser user))))
+        (format "%s|%s:%s@%s:%s"
+                (substring prefix 0 -1) method user host dir)
+      (format "/%s:%s@%s:%s" method user host dir))))
+
 (defun eshell/sudo (&rest args)
   "Alias \"sudo\" to call Tramp.
 
@@ -99,34 +115,44 @@ Uses the system sudo through TRAMP's sudo method."
    "sudo" args
    '((?h "help" nil nil "show this usage screen")
      (?u "user" t user "execute a command as another USER")
+     (?s "shell" nil shell "start a shell instead of executing COMMAND")
      :show-usage
      :parse-leading-options-only
-     :usage "[(-u | --user) USER] COMMAND
+     :usage "[(-u | --user) USER] (-s | --shell) | COMMAND
 Execute a COMMAND as the superuser or another USER.")
-   (throw 'eshell-external
-          (let* ((user (or user "root"))
-                 (host (or (file-remote-p default-directory 'host)
-                           tramp-default-host))
-                 (dir (file-local-name (expand-file-name default-directory)))
-                 (prefix (file-remote-p default-directory))
-                 (default-directory
-                   (if (and prefix
-                            (or
-                             (not
-                              (string-equal
-                               "sudo"
-                               (file-remote-p default-directory 'method)))
-                             (not
-                              (string-equal
-                               user
-                               (file-remote-p default-directory 'user)))))
-                       (format "%s|sudo:%s@%s:%s"
-                               (substring prefix 0 -1) user host dir)
-                     (format "/sudo:%s@%s:%s" user host dir))))
-            (eshell-named-command (car args) (cdr args))))))
+   (let ((dir (eshell--method-wrap-directory default-directory "sudo" user)))
+     (if shell
+         (throw 'eshell-replace-command
+                (eshell-parse-command "cd" (list dir)))
+       (throw 'eshell-external
+              (let ((default-directory dir))
+                (eshell-named-command (car args) (cdr args))))))))
 
 (put 'eshell/sudo 'eshell-no-numeric-conversions t)
 
+(defun eshell/doas (&rest args)
+  "Call Tramp's doas method with ARGS.
+
+Uses the system doas through Tramp's doas method."
+  (eshell-eval-using-options
+   "doas" args
+   '((?h "help" nil nil "show this usage screen")
+     (?u "user" t user "execute a command as another USER")
+     (?s "shell" nil shell "start a shell instead of executing COMMAND")
+     :show-usage
+     :parse-leading-options-only
+     :usage "[(-u | --user) USER] (-s | --shell) | COMMAND
+Execute a COMMAND as the superuser or another USER.")
+   (let ((dir (eshell--method-wrap-directory default-directory "doas" user)))
+     (if shell
+         (throw 'eshell-replace-command
+                (eshell-parse-command "cd" (list dir)))
+       (throw 'eshell-external
+              (let ((default-directory dir))
+                (eshell-named-command (car args) (cdr args))))))))
+
+(put 'eshell/doas 'eshell-no-numeric-conversions t)
+
 (provide 'em-tramp)
 
 ;; Local Variables:
index 8969c1e2294d125a252e0fee38c65a19e0c4812f..6cc35ecdb1b1f1fb15a72d85f5787bdcedbb9f4b 100644 (file)
              `(,(format "/sudo:USER@%s:%s" tramp-default-host default-directory)
                ("echo" ("-u" "hi")))))))
 
+(ert-deftest em-tramp-test/sudo-shell ()
+  "Test Eshell `sudo' command with -s/--shell option."
+  (dolist (args '(("--shell")
+                  ("-s")))
+    (should (equal
+             (catch 'eshell-replace-command (apply #'eshell/sudo args))
+             `(eshell-trap-errors
+               (eshell-named-command
+                "cd"
+                (list ,(format "/sudo:root@%s:%s"
+                               tramp-default-host default-directory))))))))
+
+(ert-deftest em-tramp-test/sudo-user-shell ()
+  "Test Eshell `sudo' command with -s and -u options."
+  (should (equal
+           (catch 'eshell-replace-command (eshell/sudo "-u" "USER" "-s"))
+           `(eshell-trap-errors
+             (eshell-named-command
+              "cd"
+              (list ,(format "/sudo:USER@%s:%s"
+                             tramp-default-host default-directory)))))))
+
+(ert-deftest em-tramp-test/doas-basic ()
+  "Test Eshell `doas' command with default user."
+  (cl-letf (((symbol-function 'eshell-named-command)
+             #'mock-eshell-named-command))
+    (should (equal
+             (catch 'eshell-external (eshell/doas "echo" "hi"))
+             `(,(format "/doas:root@%s:%s"
+                        tramp-default-host default-directory)
+               ("echo" ("hi")))))
+    (should (equal
+             (catch 'eshell-external (eshell/doas "echo" "-u" "hi"))
+             `(,(format "/doas:root@%s:%s"
+                        tramp-default-host default-directory)
+               ("echo" ("-u" "hi")))))))
+
+(ert-deftest em-tramp-test/doas-user ()
+  "Test Eshell `doas' command with specified user."
+  (cl-letf (((symbol-function 'eshell-named-command)
+             #'mock-eshell-named-command))
+    (should (equal
+             (catch 'eshell-external (eshell/doas "-u" "USER" "echo" "hi"))
+             `(,(format "/doas:USER@%s:%s"
+                        tramp-default-host default-directory)
+               ("echo" ("hi")))))
+    (should (equal
+             (catch 'eshell-external
+               (eshell/doas "-u" "USER" "echo" "-u" "hi"))
+             `(,(format "/doas:USER@%s:%s"
+                        tramp-default-host default-directory)
+               ("echo" ("-u" "hi")))))))
+
+(ert-deftest em-tramp-test/doas-shell ()
+  "Test Eshell `doas' command with -s/--shell option."
+  (dolist (args '(("--shell")
+                  ("-s")))
+    (should (equal
+             (catch 'eshell-replace-command (apply #'eshell/doas args))
+             `(eshell-trap-errors
+               (eshell-named-command
+                "cd"
+                (list ,(format "/doas:root@%s:%s"
+                               tramp-default-host default-directory))))))))
+
+(ert-deftest em-tramp-test/doas-user-shell ()
+  "Test Eshell `doas' command with -s and -u options."
+  (should (equal
+           (catch 'eshell-replace-command (eshell/doas "-u" "USER" "-s"))
+           `(eshell-trap-errors
+             (eshell-named-command
+              "cd"
+              (list ,(format "/doas:USER@%s:%s"
+                             tramp-default-host default-directory)))))))
+
 ;;; em-tramp-tests.el ends here