From patchwork Tue Oct 26 17:45:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Ludovic_Court=C3=A8s?= X-Patchwork-Id: 34073 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id AAFB927BBE3; Tue, 26 Oct 2021 18:52:49 +0100 (BST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,T_DKIM_INVALID, URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.2 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 394B127BBE1 for ; Tue, 26 Oct 2021 18:52:49 +0100 (BST) Received: from localhost ([::1]:57268 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mfQcy-0007HF-9P for patchwork@mira.cbaines.net; Tue, 26 Oct 2021 13:52:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:49222) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mfQWQ-0008Nx-MD for guix-patches@gnu.org; Tue, 26 Oct 2021 13:46:03 -0400 Received: from debbugs.gnu.org ([209.51.188.43]:35941) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mfQWQ-0007q8-CS for guix-patches@gnu.org; Tue, 26 Oct 2021 13:46:02 -0400 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1mfQWQ-0006ur-Am for guix-patches@gnu.org; Tue, 26 Oct 2021 13:46:02 -0400 X-Loop: help-debbugs@gnu.org Subject: [bug#51417] [PATCH] environment: Suggest command upon 'execlp' failure. Resent-From: Ludovic =?utf-8?q?Court=C3=A8s?= Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Tue, 26 Oct 2021 17:46:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 51417 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 51417@debbugs.gnu.org Cc: Ludovic =?utf-8?q?Court=C3=A8s?= X-Debbugs-Original-To: guix-patches@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.163527034326551 (code B ref -1); Tue, 26 Oct 2021 17:46:02 +0000 Received: (at submit) by debbugs.gnu.org; 26 Oct 2021 17:45:43 +0000 Received: from localhost ([127.0.0.1]:47487 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfQW7-0006uA-ER for submit@debbugs.gnu.org; Tue, 26 Oct 2021 13:45:43 -0400 Received: from lists.gnu.org ([209.51.188.17]:49522) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mfQW6-0006u3-0t for submit@debbugs.gnu.org; Tue, 26 Oct 2021 13:45:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:49204) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mfQW5-0007z7-Ht for guix-patches@gnu.org; Tue, 26 Oct 2021 13:45:41 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:36398) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mfQW4-0007js-EQ; Tue, 26 Oct 2021 13:45:40 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to: references; bh=aM8wzDqCcDdyxvwlmppAqf2GF2cZgYWod93QR6MS2s4=; b=V7hhEg/XoTAkHH 1Cs3bxGAuaSATQFe6+e71BxmbLqx3pWW1XNu8wXmoABBWbTh4WbPEHDbsS/EuRaYfCQXs+t13Fn2J GjvRQiUlbTeeaypbxLg7D9YM8m+CfAE/DU/pPZ6RXV4JJzPNyhZhQS/Jbato1p98kYq3nlW6PGLCM znx+UT4u/lxUjGktVNXS/Ze0c3qWKT4WKIR5soLERXCI0TaPY/txdLw/LsGCSBIe2AyULL7ajT0n9 I4uRGPTz77cgwyBoDWiEhbptWkZpqbWM3iP5EJtK78yvQXmlYJAtrdMQuWRHc/HEZz6HIAoy9rIr7 Mogrljy242+4e2Imtm1Q==; Received: from 91-160-117-201.subs.proxad.net ([91.160.117.201]:54226 helo=gnu.org) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mfQW4-0007Bl-08; Tue, 26 Oct 2021 13:45:40 -0400 From: Ludovic =?utf-8?q?Court=C3=A8s?= Date: Tue, 26 Oct 2021 19:45:26 +0200 Message-Id: <20211026174526.24091-1-ludo@gnu.org> X-Mailer: git-send-email 2.33.0 MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * 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’. base-commit: 0a42998a50e8bbe9e49142b21a570db00efe7491 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.