* [bug#62848] [PATCH] environment: Add --remote option and emacsclient-eshell backend. @ 2023-04-15 1:44 Antero Mejr via Guix-patches via 2023-09-01 13:26 ` Maxim Cournoyer 2023-11-07 22:30 ` [bug#62848] [PATCH v2] " Antero Mejr via Guix-patches via 0 siblings, 2 replies; 8+ messages in thread From: Antero Mejr via Guix-patches via @ 2023-04-15 1:44 UTC (permalink / raw) To: 62848; +Cc: ludo * guix/scripts/environment.scm (launch-environment/eshell): New procedure. (guix-environment*): Add logic for remote backend switching. (%options): Add --remote and --list-remote-backends options. (show-environment-options-help): Add help text for new options. * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, unsetenv-proc]: New optional keyword arguments. (purify-environment)[unsetenv-proc]: New argument. * doc/guix.texi(Invoking guix shell): Document --remote and --list-remote-backends options. --- "guix shell" doesn't support eshell due to eshell's quirks. This change makes environments/profiles more network transparent to support eshell, and maybe other remote environments in the future. doc/guix.texi | 17 ++++++++ guix/profiles.scm | 30 ++++++++------ guix/scripts/environment.scm | 80 ++++++++++++++++++++++++++++++++++-- 3 files changed, 112 insertions(+), 15 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index adb1975935..f609e0c9b6 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6245,6 +6245,23 @@ environment. @itemx -s @var{system} Attempt to build for @var{system}---e.g., @code{i686-linux}. +@item --remote=@var{backend}[=@var{args}] +Create an environment over a remote connection using @var{backend}, +optionally passing @var{args} to the backend. + +This option causes the @option{--container} option to be ignored. + +When @var{backend} is @code{emacsclient-eshell}, a new eshell buffer +with the Guix environment will be opened. An Emacs server must already +be running, and the @code{emacsclient} program must be available. Due +to the way @code{eshell} handles commands, the @var{command} argument, +if specified, will run in the initial @code{eshell} environment instead +of the Guix @code{eshell} environment. + +@item --list-remote-backends +Display the @var{backend} options for @code{guix shell --remote=BACKEND} +and exit. + @item --container @itemx -C @cindex container diff --git a/guix/profiles.scm b/guix/profiles.scm index 03333785f9..1bf6783eea 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -2062,10 +2062,10 @@ (define %precious-variables ;; Environment variables in the default 'load-profile' white list. '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" "PAGER")) -(define (purify-environment white-list white-list-regexps) +(define (purify-environment white-list white-list-regexps unsetenv-proc) "Unset all environment variables except those that match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST." - (for-each unsetenv + (for-each unsetenv-proc (remove (lambda (variable) (or (member variable white-list) (find (cut regexp-exec <> variable) @@ -2077,23 +2077,29 @@ (define (purify-environment white-list white-list-regexps) (define* (load-profile profile #:optional (manifest (profile-manifest profile)) #:key pure? (white-list-regexps '()) - (white-list %precious-variables)) + (white-list %precious-variables) + (getenv-proc getenv) (setenv-proc setenv) + (unsetenv-proc unsetenv)) "Set the environment variables specified by MANIFEST for PROFILE. When PURE? is #t, unset the variables in the current environment except those that match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. Otherwise, augment existing environment variables with additional search -paths." +paths. +GETENV-PROC is a one-argument procedure that returns an env var value. +SETENV-PROC is a two-argument procedure the sets environment variables. +UNSETENV-PROC is a one-argument procedure that unsets environment variables. +Change those procedures to load a profile over a remote connection." (when pure? - (purify-environment white-list white-list-regexps)) + (purify-environment white-list white-list-regexps unsetenv-proc)) (for-each (match-lambda ((($ <search-path-specification> variable _ separator) . value) - (let ((current (getenv variable))) - (setenv variable - (if (and current (not pure?)) - (if separator - (string-append value separator current) - value) - value))))) + (let ((current (getenv-proc variable))) + (setenv-proc variable + (if (and current (not pure?)) + (if separator + (string-append value separator current) + value) + value))))) (profile-search-paths profile manifest))) (define (profile-regexp profile) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index ebfc05731c..7e67cf1d1d 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -53,6 +53,7 @@ (define-module (guix scripts environment) #:autoload (gnu packages bootstrap) (bootstrap-executable %bootstrap-guile) #:autoload (gnu packages package-management) (guix) #:use-module (ice-9 match) + #:use-module (ice-9 popen) #:autoload (ice-9 rdelim) (read-line) #:use-module (ice-9 vlist) #:autoload (web uri) (string->uri uri-scheme) @@ -104,6 +105,13 @@ (define (show-environment-options-help) (display (G_ " -r, --root=FILE make FILE a symlink to the result, and register it as a garbage collector root")) + (display (G_ " + --remote=BACKEND[=ARGS] + create environment over a remote connection by + passing ARGS to BACKEND")) + (display (G_ " + --list-remote-backends + list available remote backends and exit")) (display (G_ " -C, --container run command within an isolated container")) (display (G_ " @@ -283,6 +291,13 @@ (define %options (option '("bootstrap") #f #f (lambda (opt name arg result) (alist-cons 'bootstrap? #t result))) + (option '("remote") #t #f + (lambda (opt name arg result) + (alist-cons 'remote arg result))) + (option '("list-remote-backends") #f #f + (lambda args + (display "emacsclient-eshell\n") + (exit 0))) (append %transformation-options %standard-build-options @@ -715,6 +730,50 @@ (define* (launch-environment/fork command profile manifest ((_ . status) status))))) +(define* (launch-environment/eshell args command profile manifest + #:key pure? (white-list '())) + "Create an new eshell buffer with an environment containing PROFILE, +with the search paths specified by MANIFEST. When PURE?, pre-existing +environment variables are cleared before setting the new ones, except those +matching the regexps in WHITE-LIST." + + (define (escape in) + (string-append "\"" (string-replace-substring in "\"" "\\\"") "\"")) + + (define* (ec cmd #:optional (check? #f)) + (let* ((cmd (string-append "emacsclient " args " -e " (escape cmd))) + (port (open-input-pipe cmd)) + (str (read-line port)) + (code (status:exit-val (close-pipe port)))) + (if (and check? (or (not (eqv? code 0)) (eof-object? str))) + (leave + (G_ "Emacs server connection failed. Is the server running?~%"))) + str)) + + (let ((buf (ec "(buffer-name (eshell t))" #t))) + (define (ec-buf cmd) + (ec (string-append "(with-current-buffer " buf " " cmd ")"))) + + (load-profile + profile manifest #:pure? pure? #:white-list-regexps white-list + #:setenv-proc (lambda (var val) + (ec-buf + (if (string=? var "PATH") + ;; TODO: TRAMP support? + (string-append "(eshell-set-path " (escape val) ")") + (string-append "(setenv " (escape var) " " + (escape val) ")")))) + #:unsetenv-proc (lambda (var) + (ec-buf + (string-append "(setenv " (escape var) ")")))) + + (match command + ((program . args) + (ec-buf + (string-append + "(eshell-command " + (escape (string-append program " " (string-join args)))")")))))) + (define* (launch-environment/container #:key command bash user user-mappings profile manifest link-profile? network? map-cwd? emulate-fhs? nesting? @@ -1081,7 +1140,10 @@ (define (guix-environment* opts) '("/bin/sh") (list %default-shell)))) (mappings (pick-all opts 'file-system-mapping)) - (white-list (pick-all opts 'inherit-regexp))) + (white-list (pick-all opts 'inherit-regexp)) + (remote (match (string-split (assoc-ref opts 'remote) #\=) + ((x) (cons x "")) + ((x . y) (cons x (string-join y)))))) (define store-needed? ;; Whether connecting to the daemon is needed. @@ -1119,6 +1181,10 @@ (define-syntax-rule (with-store/maybe store exp ...) (when (pair? symlinks) (leave (G_ "'--symlink' cannot be used without '--container~%'")))) + (when (and remote (not (member (car remote) '("emacsclient-eshell")))) + (leave + (G_ "Invalid remote backend, see --list-remote-backends for options.~%'"))) + (with-store/maybe store (with-status-verbosity (assoc-ref opts 'verbosity) (define manifest-from-opts @@ -1172,15 +1238,23 @@ (define manifest (mwhen (assoc-ref opts 'check?) (return - (if container? + (if (or container? remote) (warning (G_ "'--check' is unnecessary \ -when using '--container'; doing nothing~%")) +when using '--container' or '--remote'; doing nothing~%")) (validate-child-shell-environment profile manifest)))) (cond ((assoc-ref opts 'search-paths) (show-search-paths profile manifest #:pure? pure?) (return #t)) + (remote + (match (car remote) + ("emacsclient-eshell" + (return + (launch-environment/eshell (cdr remote) + command profile manifest + #:white-list white-list + #:pure? pure?))))) (container? (let ((bash-binary (if bootstrap? -- 2.39.2 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [bug#62848] [PATCH] environment: Add --remote option and emacsclient-eshell backend. 2023-04-15 1:44 [bug#62848] [PATCH] environment: Add --remote option and emacsclient-eshell backend Antero Mejr via Guix-patches via @ 2023-09-01 13:26 ` Maxim Cournoyer 2023-11-07 22:30 ` [bug#62848] [PATCH v2] " Antero Mejr via Guix-patches via 1 sibling, 0 replies; 8+ messages in thread From: Maxim Cournoyer @ 2023-09-01 13:26 UTC (permalink / raw) To: Antero Mejr; +Cc: ludo, 62848 Hi Antero, Antero Mejr <antero@mailbox.org> writes: > * guix/scripts/environment.scm (launch-environment/eshell): New procedure. > (guix-environment*): Add logic for remote backend switching. > (%options): Add --remote and --list-remote-backends options. > (show-environment-options-help): Add help text for new options. > * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, unsetenv-proc]: > New optional keyword arguments. > (purify-environment)[unsetenv-proc]: New argument. > * doc/guix.texi(Invoking guix shell): Document --remote and > --list-remote-backends options. This looks interesting! [...] > +(define* (launch-environment/eshell args command profile manifest > + #:key pure? (white-list '())) Maybe use the modern allow-list / block-list terminology. > + "Create an new eshell buffer with an environment containing PROFILE, > +with the search paths specified by MANIFEST. When PURE?, pre-existing > +environment variables are cleared before setting the new ones, except those > +matching the regexps in WHITE-LIST." > + > + (define (escape in) > + (string-append "\"" (string-replace-substring in "\"" "\\\"") "\"")) > + > + (define* (ec cmd #:optional (check? #f)) ^ Shouldn't we always check for errors? When is it useful to let them through? > + (let* ((cmd (string-append "emacsclient " args " -e " (escape cmd))) Instead of having to escape stuff, it'd be better to avoid using a shell for the invocation by opening the pipe with (open-pipe* OPEN_READ prog arg ...). There's an example if you grep for 'with-input-pipe-to-string' in the update-guix-package.scm file. This should make the rest of the code more readable. > + (port (open-input-pipe cmd)) > + (str (read-line port)) > + (code (status:exit-val (close-pipe port)))) > + (if (and check? (or (not (eqv? code 0)) (eof-object? str))) ^ (zero? code) > + (leave > + (G_ "Emacs server connection failed. Is the server running?~%"))) > + str)) > + > + (let ((buf (ec "(buffer-name (eshell t))" #t))) > + (define (ec-buf cmd) > + (ec (string-append "(with-current-buffer " buf " " cmd ")"))) > + > + (load-profile > + profile manifest #:pure? pure? #:white-list-regexps white-list > + #:setenv-proc (lambda (var val) > + (ec-buf > + (if (string=? var "PATH") > + ;; TODO: TRAMP support? > + (string-append "(eshell-set-path " (escape val) ")") > + (string-append "(setenv " (escape var) " " > + (escape val) ")")))) > + #:unsetenv-proc (lambda (var) > + (ec-buf > + (string-append "(setenv " (escape var) ")")))) > + > + (match command > + ((program . args) > + (ec-buf > + (string-append > + "(eshell-command " > + (escape (string-append program " " (string-join args)))")")))))) > + > (define* (launch-environment/container #:key command bash user user-mappings > profile manifest link-profile? network? > map-cwd? emulate-fhs? nesting? > @@ -1081,7 +1140,10 @@ (define (guix-environment* opts) > '("/bin/sh") > (list %default-shell)))) > (mappings (pick-all opts 'file-system-mapping)) > - (white-list (pick-all opts 'inherit-regexp))) > + (white-list (pick-all opts 'inherit-regexp)) > + (remote (match (string-split (assoc-ref opts 'remote) #\=) > + ((x) (cons x "")) Why is this needed? > + ((x . y) (cons x (string-join y)))))) If using open-pipe* as suggested above, all the arguments could be kept as a list. > > (define store-needed? > ;; Whether connecting to the daemon is needed. > @@ -1119,6 +1181,10 @@ (define-syntax-rule (with-store/maybe store exp ...) > (when (pair? symlinks) > (leave (G_ "'--symlink' cannot be used without '--container~%'")))) > > + (when (and remote (not (member (car remote) '("emacsclient-eshell")))) > + (leave > + (G_ "Invalid remote backend, see --list-remote-backends for options.~%'"))) This code and the --list-remote-backends associated procedure could share a same %supported-backends list containing currently just '("emacsclient-eshell"). > (with-store/maybe store > (with-status-verbosity (assoc-ref opts 'verbosity) > (define manifest-from-opts > @@ -1172,15 +1238,23 @@ (define manifest > > (mwhen (assoc-ref opts 'check?) > (return > - (if container? > + (if (or container? remote) > (warning (G_ "'--check' is unnecessary \ > -when using '--container'; doing nothing~%")) > +when using '--container' or '--remote'; doing nothing~%")) > (validate-child-shell-environment profile manifest)))) > > (cond > ((assoc-ref opts 'search-paths) > (show-search-paths profile manifest #:pure? pure?) > (return #t)) > + (remote > + (match (car remote) > + ("emacsclient-eshell" > + (return > + (launch-environment/eshell (cdr remote) > + command profile manifest > + #:white-list white-list > + #:pure? pure?))))) > (container? > (let ((bash-binary > (if bootstrap? It'd be nice to have a functional test for it; some inspiration could be taken from tests/build-emacs-utils.scm, which skips the test if emacs is not available. Thanks for this contribution! Could you please send a v2 taking into account the above comments? -- Thanks, Maxim ^ permalink raw reply [flat|nested] 8+ messages in thread
* [bug#62848] [PATCH v2] environment: Add --remote option and emacsclient-eshell backend. 2023-04-15 1:44 [bug#62848] [PATCH] environment: Add --remote option and emacsclient-eshell backend Antero Mejr via Guix-patches via 2023-09-01 13:26 ` Maxim Cournoyer @ 2023-11-07 22:30 ` Antero Mejr via Guix-patches via 2023-11-08 5:29 ` Liliana Marie Prikler 1 sibling, 1 reply; 8+ messages in thread From: Antero Mejr via Guix-patches via @ 2023-11-07 22:30 UTC (permalink / raw) To: 62848; +Cc: maxim.cournoyer * guix/scripts/environment.scm (launch-environment/eshell): New procedure. (%remote-backends): New variable. (guix-environment*): Add logic for remote backend switching. (launch-envrionment)[white-list]: Change keyword argument name to 'allow-list'. (launch-environment/fork)[white-list]: Change keyword argument name to 'allow-list'. (%options): Add --remote and --list-remote-backends options. (show-environment-options-help): Add help text for new options. * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, unsetenv-proc]: New optional keyword arguments. (load-profile)[white-list]: Change keyword argument name to 'allow-list'. (purify-environment)[white-list-regexps]: Change argument name to 'allow-list-regexps'. (purify-environment)[unsetenv-proc]: New argument. * guix/build/emacs-utils.scm (%emacsclient): New parameter. (emacsclient-batch-script): New procedure. * doc/guix.texi(Invoking guix shell): Document --remote and --list-remote-backends options. * tests/build-emacs-utils.scm(emacsclient-batch-script): New test. * tests/profiles.scm(load-profile): Change 'white-list' keyword argument to 'allow-list'. --- With requested changes from Maxim's review: Update white-list/allow-list terminology throughout. Always check for errors when invoking emacsclient. Simplify emacsclient invocation code by using the (guix build emacs-utils) module. Add new test to build-emacs-utils.scm for testing emacsclient. doc/guix.texi | 17 ++++++ guix/build/emacs-utils.scm | 21 +++++++ guix/profiles.scm | 42 ++++++++------ guix/scripts/environment.scm | 106 ++++++++++++++++++++++++++++------- tests/build-emacs-utils.scm | 12 +++- tests/profiles.scm | 2 +- 6 files changed, 160 insertions(+), 40 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 9f06f1c325..92a0d99db7 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6474,6 +6474,23 @@ Invoking guix shell @itemx -s @var{system} Attempt to build for @var{system}---e.g., @code{i686-linux}. +@item --remote=@var{backend}[=@var{args}] +Create an environment over a remote connection using @var{backend}, +optionally passing @var{args} to the backend. + +This option causes the @option{--container} option to be ignored. + +When @var{backend} is @code{emacsclient-eshell}, a new eshell buffer +with the Guix environment will be opened. An Emacs server must already +be running, and the @code{emacsclient} program must be available. Due +to the way @code{eshell} handles commands, the @var{command} argument, +if specified, will run in the initial @code{eshell} environment instead +of the Guix @code{eshell} environment. + +@item --list-remote-backends +Display the @var{backend} options for @code{guix shell --remote=BACKEND} +and exit. + @item --container @itemx -C @cindex container diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm index 8e12b5b6d4..e56e230efb 100644 --- a/guix/build/emacs-utils.scm +++ b/guix/build/emacs-utils.scm @@ -28,10 +28,12 @@ (define-module (guix build emacs-utils) #:use-module (srfi srfi-34) #:use-module (srfi srfi-35) #:export (%emacs + %emacsclient emacs-batch-eval emacs-batch-edit-file emacs-batch-disable-compilation emacs-batch-script + emacsclient-batch-script emacs-batch-error? emacs-batch-error-message @@ -57,6 +59,10 @@ (define %emacs ;; The `emacs' command. (make-parameter "emacs")) +(define %emacsclient + ;; A list starting with the `emacsclient' command, plus optional arguments. + (make-parameter '("emacsclient"))) + (define (expr->string expr) "Converts EXPR, an expression, into a string." (if (string? expr) @@ -107,6 +113,21 @@ (define (emacs-batch-script expr) (message (read-string (car error-pipe))))))) output)) +(define (emacsclient-batch-script expr) + "Send the Elisp code EXPR to Emacs via emacsclient and return output." + (let* ((error-pipe (pipe)) + (port (parameterize ((current-error-port (cdr error-pipe))) + (apply open-pipe* OPEN_READ + (car (%emacsclient)) "--eval" (expr->string expr) + (cdr (%emacsclient))))) + (output (read-string port)) + (status (close-pipe port))) + (close-port (cdr error-pipe)) + (unless (zero? status) + (raise (condition (&emacs-batch-error + (message (read-string (car error-pipe))))))) + (string-trim-both output (char-set-adjoin char-set:whitespace #\")))) + (define (emacs-generate-autoloads name directory) "Generate autoloads for Emacs package NAME placed in DIRECTORY." (let* ((file (string-append directory "/" name "-autoloads.el")) diff --git a/guix/profiles.scm b/guix/profiles.scm index 5d2fb8dc64..eca2b82cb3 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -2103,41 +2103,47 @@ (define* (profile-search-paths profile (list profile) getenv)) (define %precious-variables - ;; Environment variables in the default 'load-profile' white list. + ;; Environment variables in the default 'load-profile' allow list. '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" "PAGER")) -(define (purify-environment white-list white-list-regexps) +(define (purify-environment allow-list allow-list-regexps unsetenv-proc) "Unset all environment variables except those that match the regexps in -WHITE-LIST-REGEXPS and those listed in WHITE-LIST." - (for-each unsetenv +ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST." + (for-each unsetenv-proc (remove (lambda (variable) - (or (member variable white-list) + (or (member variable allow-list) (find (cut regexp-exec <> variable) - white-list-regexps))) + allow-list-regexps))) (match (get-environment-variables) (((names . _) ...) names))))) (define* (load-profile profile #:optional (manifest (profile-manifest profile)) - #:key pure? (white-list-regexps '()) - (white-list %precious-variables)) + #:key pure? (allow-list-regexps '()) + (allow-list %precious-variables) + (getenv-proc getenv) (setenv-proc setenv) + (unsetenv-proc unsetenv)) "Set the environment variables specified by MANIFEST for PROFILE. When PURE? is #t, unset the variables in the current environment except those that -match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. +match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST. Otherwise, augment existing environment variables with additional search -paths." +paths. +GETENV-PROC is a one-argument procedure that returns an env var value. +SETENV-PROC is a two-argument procedure the sets environment variables. +UNSETENV-PROC is a one-argument procedure that unsets environment variables. +Change those procedures to load a profile over a remote connection." (when pure? - (purify-environment white-list white-list-regexps)) + (purify-environment allow-list allow-list-regexps unsetenv-proc)) (for-each (match-lambda ((($ <search-path-specification> variable _ separator) . value) - (let ((current (getenv variable))) - (setenv variable - (if (and current (not pure?)) - (if separator - (string-append value separator current) - value) - value))))) + (let ((current (getenv-proc variable))) + (setenv-proc variable + (if (and current (not pure?)) + (if separator + (string-append value separator current) + value) + value))))) (profile-search-paths profile manifest))) (define (profile-regexp profile) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index 6ae3b11e39..fa033dc0ae 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2015-2023 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org> ;;; Copyright © 2022, 2023 John Kehayias <john.kehayias@protonmail.com> +;;; Copyright © 2023, Antero Mejr <antero@mailbox.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,6 +30,7 @@ (define-module (guix scripts environment) #:use-module (guix profiles) #:use-module (guix search-paths) #:use-module (guix build utils) + #:use-module (guix build emacs-utils) #:use-module (guix monads) #:use-module ((guix gexp) #:select (lower-object)) #:autoload (guix describe) (current-profile current-channels) @@ -72,6 +74,9 @@ (define-module (guix scripts environment) (define %default-shell (or (getenv "SHELL") "/bin/sh")) +(define %remote-backends + '("emacsclient-eshell")) + (define* (show-search-paths profile manifest #:key pure?) "Display the search paths of MANIFEST applied to PROFILE. When PURE? is #t, do not augment existing environment variables with additional search paths." @@ -104,6 +109,13 @@ (define (show-environment-options-help) (display (G_ " -r, --root=FILE make FILE a symlink to the result, and register it as a garbage collector root")) + (display (G_ " + --remote=BACKEND[=ARGS] + create environment over a remote connection by + passing ARGS to BACKEND")) + (display (G_ " + --list-remote-backends + list available remote backends and exit")) (display (G_ " -C, --container run command within an isolated container")) (display (G_ " @@ -287,6 +299,13 @@ (define %options (option '("bootstrap") #f #f (lambda (opt name arg result) (alist-cons 'bootstrap? #t result))) + (option '("remote") #t #f + (lambda (opt name arg result) + (alist-cons 'remote arg result))) + (option '("list-remote-backends") #f #f + (lambda args + (display (string-join %remote-backends "\n" 'suffix)) + (exit 0))) (append %transformation-options %standard-build-options @@ -485,18 +504,18 @@ (define exit/status (compose exit status->exit-code)) (define primitive-exit/status (compose primitive-exit status->exit-code)) (define* (launch-environment command profile manifest - #:key pure? (white-list '()) + #:key pure? (allow-list '()) emulate-fhs?) "Load the environment of PROFILE, which corresponds to MANIFEST, and execute COMMAND. When PURE?, pre-existing environment variables are cleared before -setting the new ones, except those matching the regexps in WHITE-LIST. When +setting the new ones, except those matching the regexps in ALLOW-LIST. When EMULATE-FHS?, first set up an FHS environment with $PATH and generate the LD cache." ;; Properly handle SIGINT, so pressing C-c in an interactive terminal ;; application works. (sigaction SIGINT SIG_DFL) (load-profile profile manifest - #:pure? pure? #:white-list-regexps white-list) + #:pure? pure? #:allow-list-regexps allow-list) ;; Give users a way to know that they're in 'guix environment', so they can ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can @@ -706,24 +725,53 @@ (define (suggest-command-name profile command) closest)))))))) (define* (launch-environment/fork command profile manifest - #:key pure? (white-list '())) + #:key pure? (allow-list '())) "Run COMMAND in a new process with an environment containing PROFILE, with the search paths specified by MANIFEST. When PURE?, pre-existing environment variables are cleared before setting the new ones, except those matching the -regexps in WHITE-LIST." +regexps in ALLOW-LIST." (match (primitive-fork) (0 (launch-environment command profile manifest #:pure? pure? - #:white-list white-list)) + #:allow-list allow-list)) (pid (match (waitpid pid) ((_ . status) status))))) +(define* (launch-environment/eshell args command profile manifest + #:key pure? (allow-list '())) + "Create an new eshell buffer with an environment containing PROFILE, +with the search paths specified by MANIFEST. When PURE?, pre-existing +environment variables are cleared before setting the new ones, except those +matching the regexps in ALLOW-LIST." + + (parameterize ((%emacsclient (cons "emacsclient" args))) + (let* ((buf (emacsclient-batch-script '(buffer-name (eshell t)))) + (ec-buf + (lambda (cmd) + (emacsclient-batch-script `(with-current-buffer ,buf ,cmd))))) + (load-profile + profile manifest #:pure? pure? #:allow-list-regexps allow-list + #:setenv-proc (lambda (var val) + (ec-buf (if (string=? var "PATH") + ;; TODO: TRAMP support? + `(eshell-set-path ,val) + `(setenv ,var ,val)))) + #:unsetenv-proc (lambda (var) + (ec-buf `(setenv ,var)))) + (match command + ((program . args) + (begin (ec-buf + `(eshell-command + ,(string-append program " " (string-join args)))) + (ec-buf '(kill-buffer)))) + (else #t))))) + (define* (launch-environment/container #:key command bash user user-mappings profile manifest link-profile? network? map-cwd? emulate-fhs? nesting? (setup-hook #f) - (symlinks '()) (white-list '())) + (symlinks '()) (allow-list '())) "Run COMMAND within a container that features the software in PROFILE. Environment variables are set according to the search paths of MANIFEST. The global shell is BASH, a file name for a GNU Bash binary in the store. When @@ -748,7 +796,7 @@ (define* (launch-environment/container #:key command bash user user-mappings added to the container. Preserve environment variables whose name matches the one of the regexps in -WHILE-LIST." +ALLOW-LIST." (define (optional-mapping->fs mapping) (and (file-exists? (file-system-mapping-source mapping)) (file-system-mapping->bind-mount mapping))) @@ -818,7 +866,7 @@ (define* (launch-environment/container #:key command bash user user-mappings (environ (filter (match-lambda ((variable . value) (find (cut regexp-exec <> variable) - white-list))) + allow-list))) (get-environment-variables))) ;; Bind-mount all requisite store items, user-specified mappings, ;; /bin/sh, the current working directory, and possibly networking @@ -931,7 +979,7 @@ (define* (launch-environment/container #:key command bash user user-mappings (override-user-dir user home cwd) home-dir)) - ;; Set environment variables that match WHITE-LIST. + ;; Set environment variables that match ALLOW-LIST. (for-each (match-lambda ((variable . value) (setenv variable value))) @@ -1081,16 +1129,19 @@ (define (guix-environment* opts) (bootstrap? (assoc-ref opts 'bootstrap?)) (system (assoc-ref opts 'system)) (profile (assoc-ref opts 'profile)) + (remote (string-split (assoc-ref opts 'remote) #\=)) (command (or (assoc-ref opts 'exec) ;; Spawn a shell if the user didn't specify ;; anything in particular. - (if container? - ;; The user's shell is likely not available - ;; within the container. - '("/bin/sh") - (list %default-shell)))) + (cond (container? + ;; The user's shell is likely not available + ;; within the container. + '("/bin/sh")) + ;; For remote, let the backend decide. + (remote '()) + (else (list %default-shell))))) (mappings (pick-all opts 'file-system-mapping)) - (white-list (pick-all opts 'inherit-regexp))) + (allow-list (pick-all opts 'inherit-regexp))) (define store-needed? ;; Whether connecting to the daemon is needed. @@ -1129,6 +1180,10 @@ (define (guix-environment* opts) (when (pair? symlinks) (leave (G_ "'--symlink' cannot be used without '--container'~%")))) + (when (and remote (not (member (car remote) %remote-backends))) + (leave + (G_ "Invalid remote backend, see --list-remote-backends for options.~%'"))) + (with-store/maybe store (with-status-verbosity (assoc-ref opts 'verbosity) (define manifest-from-opts @@ -1182,15 +1237,26 @@ (define (guix-environment* opts) (mwhen (assoc-ref opts 'check?) (return - (if container? + (if (or container? remote) (warning (G_ "'--check' is unnecessary \ -when using '--container'; doing nothing~%")) +when using '--container' or '--remote'; doing nothing~%")) (validate-child-shell-environment profile manifest)))) (cond ((assoc-ref opts 'search-paths) (show-search-paths profile manifest #:pure? pure?) (return #t)) + (remote + (match (car remote) + ("emacsclient-eshell" + (return + (launch-environment/eshell + (match (cdr remote) + ((args) (string-split args #\space)) + (_ '())) + command profile manifest + #:allow-list allow-list + #:pure? pure?))))) (container? (let ((bash-binary (if bootstrap? @@ -1203,7 +1269,7 @@ (define (guix-environment* opts) #:user-mappings mappings #:profile profile #:manifest manifest - #:white-list white-list + #:allow-list allow-list #:link-profile? link-prof? #:network? network? #:map-cwd? (not no-cwd?) @@ -1218,7 +1284,7 @@ (define (guix-environment* opts) (return (exit/status (launch-environment/fork command profile manifest - #:white-list white-list + #:allow-list allow-list #:pure? pure?))))))))))))) ;;; Local Variables: diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs-utils.scm index 4e851ed959..6b845b93b9 100644 --- a/tests/build-emacs-utils.scm +++ b/tests/build-emacs-utils.scm @@ -29,12 +29,22 @@ (define-module (test build-emacs-utils) (test-begin "build-emacs-utils") ;; Only run the following tests if emacs is present. -(test-skip (if (which "emacs") 0 5)) +(test-skip (if (which "emacs") 0 6)) (test-equal "emacs-batch-script: print foo from emacs" "foo" (emacs-batch-script '(princ "foo"))) +;; Note: If this test fails, subsequent runs might end up in a bad state. +;; Running "emacsclient -s test -e '(kill-emacs)'" should fix it. +(test-equal "emacsclient-batch-script: print foo from emacs via emacsclient" + "foo" + (begin (invoke (%emacs) "--quick" "--daemon=test") + (parameterize ((%emacsclient '("emacsclient" "-s" "test"))) + (let ((out (emacsclient-batch-script '(princ "foo")))) + (emacsclient-batch-script '(kill-emacs)) + out)))) + (test-assert "emacs-batch-script: raise &emacs-batch-error on failure" (guard (c ((emacs-batch-error? c) ;; The error message format changed between Emacs 27 and Emacs diff --git a/tests/profiles.scm b/tests/profiles.scm index 9c419ada93..1e134f5105 100644 --- a/tests/profiles.scm +++ b/tests/profiles.scm @@ -367,7 +367,7 @@ (define glibc (getenv "PATH")) (getenv "GUILE_LOAD_PATH"))) (with-environment-excursion - (load-profile profile #:pure? #t #:white-list '()) + (load-profile profile #:pure? #t #:allow-list '()) (equal? (list (string-append "PATH=" bindir)) (environ))))))) base-commit: 220759226e93d76d8d80058f69f9d8b29714bbde -- 2.41.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [bug#62848] [PATCH v2] environment: Add --remote option and emacsclient-eshell backend. 2023-11-07 22:30 ` [bug#62848] [PATCH v2] " Antero Mejr via Guix-patches via @ 2023-11-08 5:29 ` Liliana Marie Prikler 2023-11-08 15:19 ` [bug#62848] [PATCH 1/2] guix: Rename white-list to allow-list Antero Mejr via Guix-patches via ` (2 more replies) 0 siblings, 3 replies; 8+ messages in thread From: Liliana Marie Prikler @ 2023-11-08 5:29 UTC (permalink / raw) To: Antero Mejr, 62848; +Cc: maxim.cournoyer Am Dienstag, dem 07.11.2023 um 22:30 +0000 schrieb Antero Mejr: > * guix/scripts/environment.scm (launch-environment/eshell): New > procedure. > (%remote-backends): New variable. > (guix-environment*): Add logic for remote backend switching. > (launch-envrionment)[white-list]: Change keyword argument name to > 'allow-list'. You have a typo here. In general, should be (launch-environment): Rename #:white-list to #:allow-list > (launch-environment/fork)[white-list]: Change keyword argument name > to > 'allow-list'. > (%options): Add --remote and --list-remote-backends options. > (show-environment-options-help): Add help text for new options. > * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, > unsetenv-proc]: > New optional keyword arguments. > (load-profile)[white-list]: Change keyword argument name to 'allow- > list'. > (purify-environment)[white-list-regexps]: Change argument name to > 'allow-list-regexps'. > (purify-environment)[unsetenv-proc]: New argument. > * guix/build/emacs-utils.scm (%emacsclient): New parameter. > (emacsclient-batch-script): New procedure. > * doc/guix.texi(Invoking guix shell): Document --remote and > --list-remote-backends options. > * tests/build-emacs-utils.scm(emacsclient-batch-script): New test. > * tests/profiles.scm(load-profile): Change 'white-list' keyword > argument to > 'allow-list'. > --- > With requested changes from Maxim's review: > Update white-list/allow-list terminology throughout. > Always check for errors when invoking emacsclient. > Simplify emacsclient invocation code by using the > (guix build emacs-utils) module. > Add new test to build-emacs-utils.scm for testing emacsclient. You have merged two changes into one patch imho. I think it'd be better if you swapped the wording first and then added the emacsclient code. Interestingly, this still won't support emacs sans client IIUC as we anyhow have to spawn a new process. Can we (perhaps in cooperation with guix-emacs) make it so that 'guix shell' spawned from eshell does "the right thing"? Cheers ^ permalink raw reply [flat|nested] 8+ messages in thread
* [bug#62848] [PATCH 1/2] guix: Rename white-list to allow-list. 2023-11-08 5:29 ` Liliana Marie Prikler @ 2023-11-08 15:19 ` Antero Mejr via Guix-patches via 2023-11-08 15:21 ` [bug#62848] [PATCH 2/2] environment: Add --remote option and emacsclient-eshell backend Antero Mejr via Guix-patches via 2023-11-08 15:34 ` [bug#62848] [PATCH v2] " Antero Mejr via Guix-patches via 2 siblings, 0 replies; 8+ messages in thread From: Antero Mejr via Guix-patches via @ 2023-11-08 15:19 UTC (permalink / raw) To: Liliana Marie Prikler; +Cc: 62848, maxim.cournoyer * guix/profiles.scm (purify-environment): Rename white-list-regexps to allow-list-regexps. Rename white-list to allow-list. (load-profile): Rename #:white-list-regexps to #:allow-list-regexps. * guix/scripts/environment.scm (launch-environment): Rename (launch-environment/fork): Rename #:white-list-regexps to (launch-environment/container): Rename #:white-list-regexps to (guix-environment*): Rename white-list to allow-list. * tests/profiles.scm (load-profile): Rename #:white-list to #:allow-list in load-profile procedure call. --- guix/profiles.scm | 18 +++++++++--------- guix/scripts/environment.scm | 24 ++++++++++++------------ tests/profiles.scm | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/guix/profiles.scm b/guix/profiles.scm index 5d2fb8dc64..380f42c5a1 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -2103,32 +2103,32 @@ (define* (profile-search-paths profile (list profile) getenv)) (define %precious-variables - ;; Environment variables in the default 'load-profile' white list. + ;; Environment variables in the default 'load-profile' allow list. '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" "PAGER")) -(define (purify-environment white-list white-list-regexps) +(define (purify-environment allow-list allow-list-regexps) "Unset all environment variables except those that match the regexps in -WHITE-LIST-REGEXPS and those listed in WHITE-LIST." +ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST." (for-each unsetenv (remove (lambda (variable) - (or (member variable white-list) + (or (member variable allow-list) (find (cut regexp-exec <> variable) - white-list-regexps))) + allow-list-regexps))) (match (get-environment-variables) (((names . _) ...) names))))) (define* (load-profile profile #:optional (manifest (profile-manifest profile)) - #:key pure? (white-list-regexps '()) - (white-list %precious-variables)) + #:key pure? (allow-list-regexps '()) + (allow-list %precious-variables)) "Set the environment variables specified by MANIFEST for PROFILE. When PURE? is #t, unset the variables in the current environment except those that -match the regexps in WHITE-LIST-REGEXPS and those listed in WHITE-LIST. +match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST. Otherwise, augment existing environment variables with additional search paths." (when pure? - (purify-environment white-list white-list-regexps)) + (purify-environment allow-list allow-list-regexps)) (for-each (match-lambda ((($ <search-path-specification> variable _ separator) . value) (let ((current (getenv variable))) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index 6ae3b11e39..e1ab66c9ed 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -485,18 +485,18 @@ (define exit/status (compose exit status->exit-code)) (define primitive-exit/status (compose primitive-exit status->exit-code)) (define* (launch-environment command profile manifest - #:key pure? (white-list '()) + #:key pure? (allow-list '()) emulate-fhs?) "Load the environment of PROFILE, which corresponds to MANIFEST, and execute COMMAND. When PURE?, pre-existing environment variables are cleared before -setting the new ones, except those matching the regexps in WHITE-LIST. When +setting the new ones, except those matching the regexps in ALLOW-LIST. When EMULATE-FHS?, first set up an FHS environment with $PATH and generate the LD cache." ;; Properly handle SIGINT, so pressing C-c in an interactive terminal ;; application works. (sigaction SIGINT SIG_DFL) (load-profile profile manifest - #:pure? pure? #:white-list-regexps white-list) + #:pure? pure? #:allow-list-regexps allow-list) ;; Give users a way to know that they're in 'guix environment', so they can ;; adjust 'PS1' accordingly, for instance. Set it to PROFILE so users can @@ -706,15 +706,15 @@ (define (suggest-command-name profile command) closest)))))))) (define* (launch-environment/fork command profile manifest - #:key pure? (white-list '())) + #:key pure? (allow-list '())) "Run COMMAND in a new process with an environment containing PROFILE, with the search paths specified by MANIFEST. When PURE?, pre-existing environment variables are cleared before setting the new ones, except those matching the -regexps in WHITE-LIST." +regexps in ALLOW-LIST." (match (primitive-fork) (0 (launch-environment command profile manifest #:pure? pure? - #:white-list white-list)) + #:allow-list allow-list)) (pid (match (waitpid pid) ((_ . status) status))))) @@ -723,7 +723,7 @@ (define* (launch-environment/container #:key command bash user user-mappings profile manifest link-profile? network? map-cwd? emulate-fhs? nesting? (setup-hook #f) - (symlinks '()) (white-list '())) + (symlinks '()) (allow-list '())) "Run COMMAND within a container that features the software in PROFILE. Environment variables are set according to the search paths of MANIFEST. The global shell is BASH, a file name for a GNU Bash binary in the store. When @@ -818,7 +818,7 @@ (define* (launch-environment/container #:key command bash user user-mappings (environ (filter (match-lambda ((variable . value) (find (cut regexp-exec <> variable) - white-list))) + allow-list))) (get-environment-variables))) ;; Bind-mount all requisite store items, user-specified mappings, ;; /bin/sh, the current working directory, and possibly networking @@ -931,7 +931,7 @@ (define* (launch-environment/container #:key command bash user user-mappings (override-user-dir user home cwd) home-dir)) - ;; Set environment variables that match WHITE-LIST. + ;; Set environment variables that match ALLOW-LIST. (for-each (match-lambda ((variable . value) (setenv variable value))) @@ -1090,7 +1090,7 @@ (define (guix-environment* opts) '("/bin/sh") (list %default-shell)))) (mappings (pick-all opts 'file-system-mapping)) - (white-list (pick-all opts 'inherit-regexp))) + (allow-list (pick-all opts 'inherit-regexp))) (define store-needed? ;; Whether connecting to the daemon is needed. @@ -1203,7 +1203,7 @@ (define (guix-environment* opts) #:user-mappings mappings #:profile profile #:manifest manifest - #:white-list white-list + #:allow-list allow-list #:link-profile? link-prof? #:network? network? #:map-cwd? (not no-cwd?) @@ -1218,7 +1218,7 @@ (define (guix-environment* opts) (return (exit/status (launch-environment/fork command profile manifest - #:white-list white-list + #:allow-list allow-list #:pure? pure?))))))))))))) ;;; Local Variables: diff --git a/tests/profiles.scm b/tests/profiles.scm index 9c419ada93..1e134f5105 100644 --- a/tests/profiles.scm +++ b/tests/profiles.scm @@ -367,7 +367,7 @@ (define glibc (getenv "PATH")) (getenv "GUILE_LOAD_PATH"))) (with-environment-excursion - (load-profile profile #:pure? #t #:white-list '()) + (load-profile profile #:pure? #t #:allow-list '()) (equal? (list (string-append "PATH=" bindir)) (environ))))))) base-commit: 220759226e93d76d8d80058f69f9d8b29714bbde -- 2.41.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [bug#62848] [PATCH 2/2] environment: Add --remote option and emacsclient-eshell backend. 2023-11-08 5:29 ` Liliana Marie Prikler 2023-11-08 15:19 ` [bug#62848] [PATCH 1/2] guix: Rename white-list to allow-list Antero Mejr via Guix-patches via @ 2023-11-08 15:21 ` Antero Mejr via Guix-patches via 2023-11-08 19:32 ` Liliana Marie Prikler 2023-11-08 15:34 ` [bug#62848] [PATCH v2] " Antero Mejr via Guix-patches via 2 siblings, 1 reply; 8+ messages in thread From: Antero Mejr via Guix-patches via @ 2023-11-08 15:21 UTC (permalink / raw) To: Liliana Marie Prikler; +Cc: 62848, maxim.cournoyer * guix/scripts/environment.scm (launch-environment/eshell): New procedure. (%remote-backends): New variable. (guix-environment*): Add logic for remote backend switching. (%options): Add --remote and --list-remote-backends options. (show-environment-options-help): Add help text for new options. * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, unsetenv-proc]: New optional keyword arguments. (purify-environment)[unsetenv-proc]: New argument. * guix/build/emacs-utils.scm (%emacsclient): New parameter. (emacsclient-batch-script): New procedure. * doc/guix.texi(Invoking guix shell): Document --remote and --list-remote-backends options. * tests/build-emacs-utils.scm(emacsclient-batch-script): New test. --- doc/guix.texi | 17 ++++++++ guix/build/emacs-utils.scm | 21 +++++++++ guix/profiles.scm | 30 +++++++------ guix/scripts/environment.scm | 82 ++++++++++++++++++++++++++++++++---- tests/build-emacs-utils.scm | 12 +++++- 5 files changed, 141 insertions(+), 21 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 9f06f1c325..92a0d99db7 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -6474,6 +6474,23 @@ Invoking guix shell @itemx -s @var{system} Attempt to build for @var{system}---e.g., @code{i686-linux}. +@item --remote=@var{backend}[=@var{args}] +Create an environment over a remote connection using @var{backend}, +optionally passing @var{args} to the backend. + +This option causes the @option{--container} option to be ignored. + +When @var{backend} is @code{emacsclient-eshell}, a new eshell buffer +with the Guix environment will be opened. An Emacs server must already +be running, and the @code{emacsclient} program must be available. Due +to the way @code{eshell} handles commands, the @var{command} argument, +if specified, will run in the initial @code{eshell} environment instead +of the Guix @code{eshell} environment. + +@item --list-remote-backends +Display the @var{backend} options for @code{guix shell --remote=BACKEND} +and exit. + @item --container @itemx -C @cindex container diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm index 8e12b5b6d4..e56e230efb 100644 --- a/guix/build/emacs-utils.scm +++ b/guix/build/emacs-utils.scm @@ -28,10 +28,12 @@ (define-module (guix build emacs-utils) #:use-module (srfi srfi-34) #:use-module (srfi srfi-35) #:export (%emacs + %emacsclient emacs-batch-eval emacs-batch-edit-file emacs-batch-disable-compilation emacs-batch-script + emacsclient-batch-script emacs-batch-error? emacs-batch-error-message @@ -57,6 +59,10 @@ (define %emacs ;; The `emacs' command. (make-parameter "emacs")) +(define %emacsclient + ;; A list starting with the `emacsclient' command, plus optional arguments. + (make-parameter '("emacsclient"))) + (define (expr->string expr) "Converts EXPR, an expression, into a string." (if (string? expr) @@ -107,6 +113,21 @@ (define (emacs-batch-script expr) (message (read-string (car error-pipe))))))) output)) +(define (emacsclient-batch-script expr) + "Send the Elisp code EXPR to Emacs via emacsclient and return output." + (let* ((error-pipe (pipe)) + (port (parameterize ((current-error-port (cdr error-pipe))) + (apply open-pipe* OPEN_READ + (car (%emacsclient)) "--eval" (expr->string expr) + (cdr (%emacsclient))))) + (output (read-string port)) + (status (close-pipe port))) + (close-port (cdr error-pipe)) + (unless (zero? status) + (raise (condition (&emacs-batch-error + (message (read-string (car error-pipe))))))) + (string-trim-both output (char-set-adjoin char-set:whitespace #\")))) + (define (emacs-generate-autoloads name directory) "Generate autoloads for Emacs package NAME placed in DIRECTORY." (let* ((file (string-append directory "/" name "-autoloads.el")) diff --git a/guix/profiles.scm b/guix/profiles.scm index 380f42c5a1..eca2b82cb3 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -2106,10 +2106,10 @@ (define %precious-variables ;; Environment variables in the default 'load-profile' allow list. '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" "PAGER")) -(define (purify-environment allow-list allow-list-regexps) +(define (purify-environment allow-list allow-list-regexps unsetenv-proc) "Unset all environment variables except those that match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST." - (for-each unsetenv + (for-each unsetenv-proc (remove (lambda (variable) (or (member variable allow-list) (find (cut regexp-exec <> variable) @@ -2121,23 +2121,29 @@ (define (purify-environment allow-list allow-list-regexps) (define* (load-profile profile #:optional (manifest (profile-manifest profile)) #:key pure? (allow-list-regexps '()) - (allow-list %precious-variables)) + (allow-list %precious-variables) + (getenv-proc getenv) (setenv-proc setenv) + (unsetenv-proc unsetenv)) "Set the environment variables specified by MANIFEST for PROFILE. When PURE? is #t, unset the variables in the current environment except those that match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST. Otherwise, augment existing environment variables with additional search -paths." +paths. +GETENV-PROC is a one-argument procedure that returns an env var value. +SETENV-PROC is a two-argument procedure the sets environment variables. +UNSETENV-PROC is a one-argument procedure that unsets environment variables. +Change those procedures to load a profile over a remote connection." (when pure? - (purify-environment allow-list allow-list-regexps)) + (purify-environment allow-list allow-list-regexps unsetenv-proc)) (for-each (match-lambda ((($ <search-path-specification> variable _ separator) . value) - (let ((current (getenv variable))) - (setenv variable - (if (and current (not pure?)) - (if separator - (string-append value separator current) - value) - value))))) + (let ((current (getenv-proc variable))) + (setenv-proc variable + (if (and current (not pure?)) + (if separator + (string-append value separator current) + value) + value))))) (profile-search-paths profile manifest))) (define (profile-regexp profile) diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index e1ab66c9ed..fa033dc0ae 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2015-2023 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org> ;;; Copyright © 2022, 2023 John Kehayias <john.kehayias@protonmail.com> +;;; Copyright © 2023, Antero Mejr <antero@mailbox.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,6 +30,7 @@ (define-module (guix scripts environment) #:use-module (guix profiles) #:use-module (guix search-paths) #:use-module (guix build utils) + #:use-module (guix build emacs-utils) #:use-module (guix monads) #:use-module ((guix gexp) #:select (lower-object)) #:autoload (guix describe) (current-profile current-channels) @@ -72,6 +74,9 @@ (define-module (guix scripts environment) (define %default-shell (or (getenv "SHELL") "/bin/sh")) +(define %remote-backends + '("emacsclient-eshell")) + (define* (show-search-paths profile manifest #:key pure?) "Display the search paths of MANIFEST applied to PROFILE. When PURE? is #t, do not augment existing environment variables with additional search paths." @@ -104,6 +109,13 @@ (define (show-environment-options-help) (display (G_ " -r, --root=FILE make FILE a symlink to the result, and register it as a garbage collector root")) + (display (G_ " + --remote=BACKEND[=ARGS] + create environment over a remote connection by + passing ARGS to BACKEND")) + (display (G_ " + --list-remote-backends + list available remote backends and exit")) (display (G_ " -C, --container run command within an isolated container")) (display (G_ " @@ -287,6 +299,13 @@ (define %options (option '("bootstrap") #f #f (lambda (opt name arg result) (alist-cons 'bootstrap? #t result))) + (option '("remote") #t #f + (lambda (opt name arg result) + (alist-cons 'remote arg result))) + (option '("list-remote-backends") #f #f + (lambda args + (display (string-join %remote-backends "\n" 'suffix)) + (exit 0))) (append %transformation-options %standard-build-options @@ -719,6 +738,35 @@ (define* (launch-environment/fork command profile manifest ((_ . status) status))))) +(define* (launch-environment/eshell args command profile manifest + #:key pure? (allow-list '())) + "Create an new eshell buffer with an environment containing PROFILE, +with the search paths specified by MANIFEST. When PURE?, pre-existing +environment variables are cleared before setting the new ones, except those +matching the regexps in ALLOW-LIST." + + (parameterize ((%emacsclient (cons "emacsclient" args))) + (let* ((buf (emacsclient-batch-script '(buffer-name (eshell t)))) + (ec-buf + (lambda (cmd) + (emacsclient-batch-script `(with-current-buffer ,buf ,cmd))))) + (load-profile + profile manifest #:pure? pure? #:allow-list-regexps allow-list + #:setenv-proc (lambda (var val) + (ec-buf (if (string=? var "PATH") + ;; TODO: TRAMP support? + `(eshell-set-path ,val) + `(setenv ,var ,val)))) + #:unsetenv-proc (lambda (var) + (ec-buf `(setenv ,var)))) + (match command + ((program . args) + (begin (ec-buf + `(eshell-command + ,(string-append program " " (string-join args)))) + (ec-buf '(kill-buffer)))) + (else #t))))) + (define* (launch-environment/container #:key command bash user user-mappings profile manifest link-profile? network? map-cwd? emulate-fhs? nesting? @@ -748,7 +796,7 @@ (define* (launch-environment/container #:key command bash user user-mappings added to the container. Preserve environment variables whose name matches the one of the regexps in -WHILE-LIST." +ALLOW-LIST." (define (optional-mapping->fs mapping) (and (file-exists? (file-system-mapping-source mapping)) (file-system-mapping->bind-mount mapping))) @@ -1081,14 +1129,17 @@ (define (guix-environment* opts) (bootstrap? (assoc-ref opts 'bootstrap?)) (system (assoc-ref opts 'system)) (profile (assoc-ref opts 'profile)) + (remote (string-split (assoc-ref opts 'remote) #\=)) (command (or (assoc-ref opts 'exec) ;; Spawn a shell if the user didn't specify ;; anything in particular. - (if container? - ;; The user's shell is likely not available - ;; within the container. - '("/bin/sh") - (list %default-shell)))) + (cond (container? + ;; The user's shell is likely not available + ;; within the container. + '("/bin/sh")) + ;; For remote, let the backend decide. + (remote '()) + (else (list %default-shell))))) (mappings (pick-all opts 'file-system-mapping)) (allow-list (pick-all opts 'inherit-regexp))) @@ -1129,6 +1180,10 @@ (define (guix-environment* opts) (when (pair? symlinks) (leave (G_ "'--symlink' cannot be used without '--container'~%")))) + (when (and remote (not (member (car remote) %remote-backends))) + (leave + (G_ "Invalid remote backend, see --list-remote-backends for options.~%'"))) + (with-store/maybe store (with-status-verbosity (assoc-ref opts 'verbosity) (define manifest-from-opts @@ -1182,15 +1237,26 @@ (define (guix-environment* opts) (mwhen (assoc-ref opts 'check?) (return - (if container? + (if (or container? remote) (warning (G_ "'--check' is unnecessary \ -when using '--container'; doing nothing~%")) +when using '--container' or '--remote'; doing nothing~%")) (validate-child-shell-environment profile manifest)))) (cond ((assoc-ref opts 'search-paths) (show-search-paths profile manifest #:pure? pure?) (return #t)) + (remote + (match (car remote) + ("emacsclient-eshell" + (return + (launch-environment/eshell + (match (cdr remote) + ((args) (string-split args #\space)) + (_ '())) + command profile manifest + #:allow-list allow-list + #:pure? pure?))))) (container? (let ((bash-binary (if bootstrap? diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs-utils.scm index 4e851ed959..6b845b93b9 100644 --- a/tests/build-emacs-utils.scm +++ b/tests/build-emacs-utils.scm @@ -29,12 +29,22 @@ (define-module (test build-emacs-utils) (test-begin "build-emacs-utils") ;; Only run the following tests if emacs is present. -(test-skip (if (which "emacs") 0 5)) +(test-skip (if (which "emacs") 0 6)) (test-equal "emacs-batch-script: print foo from emacs" "foo" (emacs-batch-script '(princ "foo"))) +;; Note: If this test fails, subsequent runs might end up in a bad state. +;; Running "emacsclient -s test -e '(kill-emacs)'" should fix it. +(test-equal "emacsclient-batch-script: print foo from emacs via emacsclient" + "foo" + (begin (invoke (%emacs) "--quick" "--daemon=test") + (parameterize ((%emacsclient '("emacsclient" "-s" "test"))) + (let ((out (emacsclient-batch-script '(princ "foo")))) + (emacsclient-batch-script '(kill-emacs)) + out)))) + (test-assert "emacs-batch-script: raise &emacs-batch-error on failure" (guard (c ((emacs-batch-error? c) ;; The error message format changed between Emacs 27 and Emacs -- 2.41.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [bug#62848] [PATCH 2/2] environment: Add --remote option and emacsclient-eshell backend. 2023-11-08 15:21 ` [bug#62848] [PATCH 2/2] environment: Add --remote option and emacsclient-eshell backend Antero Mejr via Guix-patches via @ 2023-11-08 19:32 ` Liliana Marie Prikler 0 siblings, 0 replies; 8+ messages in thread From: Liliana Marie Prikler @ 2023-11-08 19:32 UTC (permalink / raw) To: Antero Mejr; +Cc: 62848, maxim.cournoyer Am Mittwoch, dem 08.11.2023 um 15:21 +0000 schrieb Antero Mejr: > * guix/scripts/environment.scm (launch-environment/eshell): New > procedure. > (%remote-backends): New variable. > (guix-environment*): Add logic for remote backend switching. > (%options): Add --remote and --list-remote-backends options. > (show-environment-options-help): Add help text for new options. > * guix/profiles.scm (load-profile)[getenv-proc, setenv-proc, > unsetenv-proc]: > New optional keyword arguments. > (purify-environment)[unsetenv-proc]: New argument. > * guix/build/emacs-utils.scm (%emacsclient): New parameter. > (emacsclient-batch-script): New procedure. > * doc/guix.texi(Invoking guix shell): Document --remote and > --list-remote-backends options. > * tests/build-emacs-utils.scm(emacsclient-batch-script): New test. > > --- > doc/guix.texi | 17 ++++++++ > guix/build/emacs-utils.scm | 21 +++++++++ > guix/profiles.scm | 30 +++++++------ > guix/scripts/environment.scm | 82 ++++++++++++++++++++++++++++++++-- > -- > tests/build-emacs-utils.scm | 12 +++++- > 5 files changed, 141 insertions(+), 21 deletions(-) > > diff --git a/doc/guix.texi b/doc/guix.texi > index 9f06f1c325..92a0d99db7 100644 > --- a/doc/guix.texi > +++ b/doc/guix.texi > @@ -6474,6 +6474,23 @@ Invoking guix shell > @itemx -s @var{system} > Attempt to build for @var{system}---e.g., @code{i686-linux}. > > +@item --remote=@var{backend}[=@var{args}] > +Create an environment over a remote connection using @var{backend}, > +optionally passing @var{args} to the backend. > + > +This option causes the @option{--container} option to be ignored. > + > +When @var{backend} is @code{emacsclient-eshell}, a new eshell buffer > +with the Guix environment will be opened. An Emacs server must > already > +be running, and the @code{emacsclient} program must be available. > Due > +to the way @code{eshell} handles commands, the @var{command} > argument, > +if specified, will run in the initial @code{eshell} environment > instead > +of the Guix @code{eshell} environment. > + > +@item --list-remote-backends > +Display the @var{backend} options for @code{guix shell -- > remote=BACKEND} > +and exit. > + > @item --container > @itemx -C > @cindex container > diff --git a/guix/build/emacs-utils.scm b/guix/build/emacs-utils.scm > index 8e12b5b6d4..e56e230efb 100644 > --- a/guix/build/emacs-utils.scm > +++ b/guix/build/emacs-utils.scm > @@ -28,10 +28,12 @@ (define-module (guix build emacs-utils) > #:use-module (srfi srfi-34) > #:use-module (srfi srfi-35) > #:export (%emacs > + %emacsclient > emacs-batch-eval > emacs-batch-edit-file > emacs-batch-disable-compilation > emacs-batch-script > + emacsclient-batch-script > > emacs-batch-error? > emacs-batch-error-message > @@ -57,6 +59,10 @@ (define %emacs > ;; The `emacs' command. > (make-parameter "emacs")) > > +(define %emacsclient > + ;; A list starting with the `emacsclient' command, plus optional > arguments. > + (make-parameter '("emacsclient"))) > + I think we should have emacsclient as a string parameter analogous to emacs itself. > (define (expr->string expr) > "Converts EXPR, an expression, into a string." > (if (string? expr) > @@ -107,6 +113,21 @@ (define (emacs-batch-script expr) > (message (read-string (car error- > pipe))))))) > output)) > > +(define (emacsclient-batch-script expr) > + "Send the Elisp code EXPR to Emacs via emacsclient and return > output." > + (let* ((error-pipe (pipe)) > + (port (parameterize ((current-error-port (cdr error-pipe))) > + (apply open-pipe* OPEN_READ > + (car (%emacsclient)) "--eval" (expr->string > expr) > + (cdr (%emacsclient))))) Instead of passing extra parameters via %emacsclient, how about using additional (keyword) arguments? I think #:socket-name and #:server- file are obvious ones to have, but for the purpose here you might also add a catch-all #:client-arguments which defaults to '(). > + (output (read-string port)) > + (status (close-pipe port))) > + (close-port (cdr error-pipe)) > + (unless (zero? status) > + (raise (condition (&emacs-batch-error > + (message (read-string (car error- > pipe))))))) > + (string-trim-both output (char-set-adjoin char-set:whitespace > #\")))) > + > (define (emacs-generate-autoloads name directory) > "Generate autoloads for Emacs package NAME placed in DIRECTORY." > (let* ((file (string-append directory "/" name "-autoloads.el")) > diff --git a/guix/profiles.scm b/guix/profiles.scm > index 380f42c5a1..eca2b82cb3 100644 > --- a/guix/profiles.scm > +++ b/guix/profiles.scm > @@ -2106,10 +2106,10 @@ (define %precious-variables > ;; Environment variables in the default 'load-profile' allow list. > '("HOME" "USER" "LOGNAME" "DISPLAY" "XAUTHORITY" "TERM" "TZ" > "PAGER")) > > -(define (purify-environment allow-list allow-list-regexps) > +(define (purify-environment allow-list allow-list-regexps unsetenv- > proc) You might want to use #:optional or #:key (unsetenv unsetenv) here. > "Unset all environment variables except those that match the > regexps in > ALLOW-LIST-REGEXPS and those listed in ALLOW-LIST." > - (for-each unsetenv > + (for-each unsetenv-proc > (remove (lambda (variable) > (or (member variable allow-list) > (find (cut regexp-exec <> variable) > @@ -2121,23 +2121,29 @@ (define (purify-environment allow-list allow- > list-regexps) > (define* (load-profile profile > #:optional (manifest (profile-manifest > profile)) > #:key pure? (allow-list-regexps '()) > - (allow-list %precious-variables)) > + (allow-list %precious-variables) > + (getenv-proc getenv) (setenv-proc setenv) > + (unsetenv-proc unsetenv)) Same here, you can just shadow getenv et al. > "Set the environment variables specified by MANIFEST for PROFILE. > When > PURE? is #t, unset the variables in the current environment except > those that > match the regexps in ALLOW-LIST-REGEXPS and those listed in ALLOW- > LIST. > Otherwise, augment existing environment variables with additional > search > -paths." > +paths. > +GETENV-PROC is a one-argument procedure that returns an env var > value. > +SETENV-PROC is a two-argument procedure the sets environment > variables. > +UNSETENV-PROC is a one-argument procedure that unsets environment > variables. > +Change those procedures to load a profile over a remote connection." > (when pure? > - (purify-environment allow-list allow-list-regexps)) > + (purify-environment allow-list allow-list-regexps unsetenv- > proc)) > (for-each (match-lambda > ((($ <search-path-specification> variable _ separator) > . value) > - (let ((current (getenv variable))) > - (setenv variable > - (if (and current (not pure?)) > - (if separator > - (string-append value separator > current) > - value) > - value))))) > + (let ((current (getenv-proc variable))) > + (setenv-proc variable > + (if (and current (not pure?)) > + (if separator > + (string-append value separator > current) > + value) > + value))))) > (profile-search-paths profile manifest))) > > (define (profile-regexp profile) > diff --git a/guix/scripts/environment.scm > b/guix/scripts/environment.scm > index e1ab66c9ed..fa033dc0ae 100644 > --- a/guix/scripts/environment.scm > +++ b/guix/scripts/environment.scm > @@ -3,6 +3,7 @@ > ;;; Copyright © 2015-2023 Ludovic Courtès <ludo@gnu.org> > ;;; Copyright © 2018 Mike Gerwitz <mtg@gnu.org> > ;;; Copyright © 2022, 2023 John Kehayias > <john.kehayias@protonmail.com> > +;;; Copyright © 2023, Antero Mejr <antero@mailbox.org> > ;;; > ;;; This file is part of GNU Guix. > ;;; > @@ -29,6 +30,7 @@ (define-module (guix scripts environment) > #:use-module (guix profiles) > #:use-module (guix search-paths) > #:use-module (guix build utils) > + #:use-module (guix build emacs-utils) > #:use-module (guix monads) > #:use-module ((guix gexp) #:select (lower-object)) > #:autoload (guix describe) (current-profile current-channels) > @@ -72,6 +74,9 @@ (define-module (guix scripts environment) > (define %default-shell > (or (getenv "SHELL") "/bin/sh")) > > +(define %remote-backends > + '("emacsclient-eshell")) > + > (define* (show-search-paths profile manifest #:key pure?) > "Display the search paths of MANIFEST applied to PROFILE. When > PURE? is #t, > do not augment existing environment variables with additional search > paths." > @@ -104,6 +109,13 @@ (define (show-environment-options-help) > (display (G_ " > -r, --root=FILE make FILE a symlink to the result, and > register it > as a garbage collector root")) > + (display (G_ " > + --remote=BACKEND[=ARGS] > + create environment over a remote connection > by > + passing ARGS to BACKEND")) > + (display (G_ " > + --list-remote-backends > + list available remote backends and exit")) > (display (G_ " > -C, --container run command within an isolated container")) > (display (G_ " > @@ -287,6 +299,13 @@ (define %options > (option '("bootstrap") #f #f > (lambda (opt name arg result) > (alist-cons 'bootstrap? #t result))) > + (option '("remote") #t #f > + (lambda (opt name arg result) > + (alist-cons 'remote arg result))) > + (option '("list-remote-backends") #f #f > + (lambda args > + (display (string-join %remote-backends "\n" > 'suffix)) > + (exit 0))) > > (append %transformation-options > %standard-build-options > @@ -719,6 +738,35 @@ (define* (launch-environment/fork command > profile manifest > ((_ . status) > status))))) > > +(define* (launch-environment/eshell args command profile manifest > + #:key pure? (allow-list '())) > + "Create an new eshell buffer with an environment containing > PROFILE, > +with the search paths specified by MANIFEST. When PURE?, pre- > existing > +environment variables are cleared before setting the new ones, > except those > +matching the regexps in ALLOW-LIST." > + > + (parameterize ((%emacsclient (cons "emacsclient" args))) > + (let* ((buf (emacsclient-batch-script '(buffer-name (eshell > t)))) > + (ec-buf > + (lambda (cmd) > + (emacsclient-batch-script `(with-current-buffer ,buf > ,cmd))))) > + (load-profile > + profile manifest #:pure? pure? #:allow-list-regexps allow-list > + #:setenv-proc (lambda (var val) > + (ec-buf (if (string=? var "PATH") > + ;; TODO: TRAMP support? > + `(eshell-set-path ,val) > + `(setenv ,var ,val)))) > + #:unsetenv-proc (lambda (var) > + (ec-buf `(setenv ,var)))) > + (match command > + ((program . args) > + (begin (ec-buf > + `(eshell-command > + ,(string-append program " " (string-join args)))) > + (ec-buf '(kill-buffer)))) > + (else #t))))) > + > (define* (launch-environment/container #:key command bash user user- > mappings > profile manifest link- > profile? network? > map-cwd? emulate-fhs? > nesting? > @@ -748,7 +796,7 @@ (define* (launch-environment/container #:key > command bash user user-mappings > added to the container. > > Preserve environment variables whose name matches the one of the > regexps in > -WHILE-LIST." > +ALLOW-LIST." > (define (optional-mapping->fs mapping) > (and (file-exists? (file-system-mapping-source mapping)) > (file-system-mapping->bind-mount mapping))) > @@ -1081,14 +1129,17 @@ (define (guix-environment* opts) > (bootstrap? (assoc-ref opts 'bootstrap?)) > (system (assoc-ref opts 'system)) > (profile (assoc-ref opts 'profile)) > + (remote (string-split (assoc-ref opts 'remote) #\=)) You might want to align the RHS here. Also, think about the possibility of "=" turning up in the remote arguments. > (command (or (assoc-ref opts 'exec) > ;; Spawn a shell if the user didn't specify > ;; anything in particular. > - (if container? > - ;; The user's shell is likely not > available > - ;; within the container. > - '("/bin/sh") > - (list %default-shell)))) > + (cond (container? > + ;; The user's shell is likely not > available > + ;; within the container. > + '("/bin/sh")) > + ;; For remote, let the backend decide. > + (remote '()) > + (else (list %default-shell))))) > (mappings (pick-all opts 'file-system-mapping)) > (allow-list (pick-all opts 'inherit-regexp))) > > @@ -1129,6 +1180,10 @@ (define (guix-environment* opts) > (when (pair? symlinks) > (leave (G_ "'--symlink' cannot be used without '-- > container'~%")))) > > + (when (and remote (not (member (car remote) %remote-backends))) > + (leave > + (G_ "Invalid remote backend, see --list-remote-backends for > options.~%'"))) > + > (with-store/maybe store > (with-status-verbosity (assoc-ref opts 'verbosity) > (define manifest-from-opts > @@ -1182,15 +1237,26 @@ (define (guix-environment* opts) > > (mwhen (assoc-ref opts 'check?) > (return > - (if container? > + (if (or container? remote) > (warning (G_ "'--check' is unnecessary \ > -when using '--container'; doing nothing~%")) > +when using '--container' or '--remote'; doing nothing~%")) > (validate-child-shell-environment profile > manifest)))) > > (cond > ((assoc-ref opts 'search-paths) > (show-search-paths profile manifest #:pure? pure?) > (return #t)) > + (remote > + (match (car remote) > + ("emacsclient-eshell" > + (return > + (launch-environment/eshell > + (match (cdr remote) > + ((args) (string-split args #\space)) > + (_ '())) > + command profile manifest > + #:allow-list allow-list > + #:pure? pure?))))) You can match the car and cdr in one go. Your string-split code also ignores the way whitespace is typically handled (and escaped!) in shells, which may or may not go well. > (container? > (let ((bash-binary > (if bootstrap? > diff --git a/tests/build-emacs-utils.scm b/tests/build-emacs- > utils.scm > index 4e851ed959..6b845b93b9 100644 > --- a/tests/build-emacs-utils.scm > +++ b/tests/build-emacs-utils.scm > @@ -29,12 +29,22 @@ (define-module (test build-emacs-utils) > > (test-begin "build-emacs-utils") > ;; Only run the following tests if emacs is present. > -(test-skip (if (which "emacs") 0 5)) > +(test-skip (if (which "emacs") 0 6)) > > (test-equal "emacs-batch-script: print foo from emacs" > "foo" > (emacs-batch-script '(princ "foo"))) > > +;; Note: If this test fails, subsequent runs might end up in a bad > state. > +;; Running "emacsclient -s test -e '(kill-emacs)'" should fix it. > +(test-equal "emacsclient-batch-script: print foo from emacs via > emacsclient" > + "foo" > + (begin (invoke (%emacs) "--quick" "--daemon=test") > + (parameterize ((%emacsclient '("emacsclient" "-s" "test"))) > + (let ((out (emacsclient-batch-script '(princ "foo")))) > + (emacsclient-batch-script '(kill-emacs)) > + out)))) > + > (test-assert "emacs-batch-script: raise &emacs-batch-error on > failure" > (guard (c ((emacs-batch-error? c) > ;; The error message format changed between Emacs 27 > and Emacs Cheers ^ permalink raw reply [flat|nested] 8+ messages in thread
* [bug#62848] [PATCH v2] environment: Add --remote option and emacsclient-eshell backend. 2023-11-08 5:29 ` Liliana Marie Prikler 2023-11-08 15:19 ` [bug#62848] [PATCH 1/2] guix: Rename white-list to allow-list Antero Mejr via Guix-patches via 2023-11-08 15:21 ` [bug#62848] [PATCH 2/2] environment: Add --remote option and emacsclient-eshell backend Antero Mejr via Guix-patches via @ 2023-11-08 15:34 ` Antero Mejr via Guix-patches via 2 siblings, 0 replies; 8+ messages in thread From: Antero Mejr via Guix-patches via @ 2023-11-08 15:34 UTC (permalink / raw) To: Liliana Marie Prikler; +Cc: 62848, maxim.cournoyer Liliana Marie Prikler <liliana.prikler@gmail.com> writes: > You have merged two changes into one patch imho. I think it'd be > better if you swapped the wording first and then added the emacsclient > code. Fixed in updated patch set. > Interestingly, this still won't support emacs sans client IIUC as we > anyhow have to spawn a new process. Can we (perhaps in cooperation > with guix-emacs) make it so that 'guix shell' spawned from eshell does > "the right thing"? Not 100% sure what you mean, but I do not think it is possible to start eshell (or interact with an existing eshell) without using emacsclient or starting a new emacs process. Starting a new emacs process is cumbersome and doesn't make sense to me - I wouldn't want to start another instance of emacs just to use a guix shell environment. Currently, running guix shell in eshellwill invoke $SHELL, which seems like the "right thing" but isn't very useful, since then you lose all the eshell features. The intention of this patch is that the user will have an emacs server already running, via the forthcoming 'home-emacs-service-type' service or some other method. Then guix shell can communicate with that server to set up the environment in a new eshell buffer. ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2023-11-08 19:34 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-04-15 1:44 [bug#62848] [PATCH] environment: Add --remote option and emacsclient-eshell backend Antero Mejr via Guix-patches via 2023-09-01 13:26 ` Maxim Cournoyer 2023-11-07 22:30 ` [bug#62848] [PATCH v2] " Antero Mejr via Guix-patches via 2023-11-08 5:29 ` Liliana Marie Prikler 2023-11-08 15:19 ` [bug#62848] [PATCH 1/2] guix: Rename white-list to allow-list Antero Mejr via Guix-patches via 2023-11-08 15:21 ` [bug#62848] [PATCH 2/2] environment: Add --remote option and emacsclient-eshell backend Antero Mejr via Guix-patches via 2023-11-08 19:32 ` Liliana Marie Prikler 2023-11-08 15:34 ` [bug#62848] [PATCH v2] " Antero Mejr via Guix-patches via
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/guix.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).