* [bug#51417] [PATCH] environment: Suggest command upon 'execlp' failure.
@ 2021-10-26 17:45 Ludovic Courtès
2021-11-06 22:23 ` bug#51417: " Ludovic Courtès
0 siblings, 1 reply; 2+ messages in thread
From: Ludovic Courtès @ 2021-10-26 17:45 UTC (permalink / raw)
To: 51417; +Cc: Ludovic Courtès
* guix/scripts/environment.scm (launch-environment): Call
'primitive-_exit' upon 'system-error.
(suggest-command-name, validate-exit-status): New procedures.
(launch-environment/fork): Call 'validate-exit-status'.
(launch-environment/container)[exit/status*]: New procedure.
Use it instead of 'exit/status'.
---
guix/scripts/environment.scm | 48 +++++++++++++++++++++++++++++++++---
1 file changed, 45 insertions(+), 3 deletions(-)
Hi!
Here’s the idea:
--8<---------------cut here---------------start------------->8---
$ ./pre-inst-env guix shell coreutils -C -- name
guix shell: error: name: command not found
hint: Did you mean 'uname'?
$ ./pre-inst-env guix shell ungoogled-chromium -- ungoogled-chromium
guix shell: error: ungoogled-chromium: command not found
hint: Did you mean 'chromium'?
$ ./pre-inst-env guix shell supertuxkart -- supertuxcart
guix shell: error: supertuxcart: command not found
hint: Did you mean 'supertuxkart'?
--8<---------------cut here---------------end--------------->8---
Thoughts?
Ludo’.
diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm
index 7b97a8e39a..fc55151254 100644
--- a/guix/scripts/environment.scm
+++ b/guix/scripts/environment.scm
@@ -34,6 +34,7 @@ (define-module (guix scripts environment)
#:use-module (guix scripts)
#:use-module (guix scripts build)
#:use-module (guix transformations)
+ #:autoload (ice-9 ftw) (scandir)
#:autoload (gnu build linux-container) (call-with-container %namespaces
user-namespace-supported?
unprivileged-user-namespace-supported?
@@ -401,7 +402,12 @@ (define* (launch-environment command profile manifest
(match command
((program . args)
- (apply execlp program program args))))
+ (catch 'system-error
+ (lambda ()
+ (apply execlp program program args))
+ (lambda _
+ ;; Following established convention, exit with 127 upon ENOENT.
+ (primitive-_exit 127))))))
(define (child-shell-environment shell profile manifest)
"Create a child process, load PROFILE and MANIFEST, and then run SHELL in
@@ -552,6 +558,38 @@ (define-syntax-rule (warn exp ...)
(info (G_ "All is good! The shell gets correct environment \
variables.~%")))))
+(define (suggest-command-name profile command)
+ "COMMAND was not found in PROFILE so display a hint suggesting the closest
+command name."
+ (define not-dot?
+ (match-lambda
+ ((or "." "..") #f)
+ (_ #t)))
+
+ (match (scandir (string-append profile "/bin") not-dot?)
+ (() #f)
+ (available
+ (match command
+ ((executable _ ...)
+ ;; Look for a suggestion with a high threshold: a suggestion is
+ ;; usually better than no suggestion.
+ (let ((closest (string-closest executable available
+ #:threshold 12)))
+ (unless (or (not closest) (string=? closest executable))
+ (display-hint (format #f (G_ "Did you mean '~a'?~%")
+ closest)))))))))
+
+(define (validate-exit-status profile command status)
+ "When STATUS, an integer as returned by 'waitpid', is 127, raise a \"command
+not found\" error. Otherwise return STATUS."
+ ;; Most likely, exit value 127 means ENOENT.
+ (when (eqv? (status:exit-val status) 127)
+ (report-error (G_ "~a: command not found~%")
+ (first command))
+ (suggest-command-name profile command)
+ (exit 1))
+ status)
+
(define* (launch-environment/fork command profile manifest
#:key pure? (white-list '()))
"Run COMMAND in a new process with an environment containing PROFILE, with
@@ -563,7 +601,8 @@ (define* (launch-environment/fork command profile manifest
#:pure? pure?
#:white-list white-list))
(pid (match (waitpid pid)
- ((_ . status) status)))))
+ ((_ . status)
+ (validate-exit-status profile command status))))))
(define* (launch-environment/container #:key command bash user user-mappings
profile manifest link-profile? network?
@@ -584,6 +623,9 @@ (define (optional-mapping->fs mapping)
(and (file-exists? (file-system-mapping-source mapping))
(file-system-mapping->bind-mount mapping)))
+ (define (exit/status* status)
+ (exit/status (validate-exit-status profile command status)))
+
(mlet %store-monad ((reqs (inputs->requisites
(list (direct-store-path bash) profile))))
(return
@@ -640,7 +682,7 @@ (define (optional-mapping->fs mapping)
'())
(map file-system-mapping->bind-mount
mappings))))
- (exit/status
+ (exit/status*
(call-with-container file-systems
(lambda ()
;; Setup global shell.
base-commit: 0a42998a50e8bbe9e49142b21a570db00efe7491
--
2.33.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* bug#51417: [PATCH] environment: Suggest command upon 'execlp' failure.
2021-10-26 17:45 [bug#51417] [PATCH] environment: Suggest command upon 'execlp' failure Ludovic Courtès
@ 2021-11-06 22:23 ` Ludovic Courtès
0 siblings, 0 replies; 2+ messages in thread
From: Ludovic Courtès @ 2021-11-06 22:23 UTC (permalink / raw)
To: 51417-done
Ludovic Courtès <ludo@gnu.org> skribis:
> * guix/scripts/environment.scm (launch-environment): Call
> 'primitive-_exit' upon 'system-error.
> (suggest-command-name, validate-exit-status): New procedures.
> (launch-environment/fork): Call 'validate-exit-status'.
> (launch-environment/container)[exit/status*]: New procedure.
> Use it instead of 'exit/status'.
Pushed in 5d2d87fed7efcb8f0cee040125f7768bab3df3f4.
Ludo’.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-11-06 22:24 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-26 17:45 [bug#51417] [PATCH] environment: Suggest command upon 'execlp' failure Ludovic Courtès
2021-11-06 22:23 ` bug#51417: " Ludovic Courtès
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).