unofficial mirror of bug-guix@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] Add 'guix hash'.
@ 2013-04-01  5:06 Nikita Karetnikov
  2013-04-03  8:34 ` Ludovic Courtès
  0 siblings, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-01  5:06 UTC (permalink / raw)
  To: bug-guix


[-- Attachment #1.1: Type: text/plain, Size: 474 bytes --]

This patch adds a 'guix hash' command.

I'd like it to output non-Base32 too, but I haven't found a way to
convert the output of 'sha256', which is a bytevector, to a string.

What options would you like to see implemented?

Should we capitalize error messages?  The current one was copied from
'guix import'.

Is it OK to output a backtrace when the specified file doesn't exist?

For example:

  # ./pre-inst-env guix hash foobar

Should we only print the error message?


[-- Attachment #1.2: 0001-Add-guix-hash.patch --]
[-- Type: text/x-diff, Size: 3943 bytes --]

From 8de1cfe973c1c0897a959250dad95048f12833b7 Mon Sep 17 00:00:00 2001
From: Nikita Karetnikov <nikita@karetnikov.org>
Date: Mon, 1 Apr 2013 04:48:02 +0000
Subject: [PATCH] Add 'guix hash'.

* guix/scripts/hash.scm: New file.
* Makefile.am (MODULES): Add it.
---
 Makefile.am           |    1 +
 guix/scripts/hash.scm |   90 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+), 0 deletions(-)
 create mode 100644 guix/scripts/hash.scm

diff --git a/Makefile.am b/Makefile.am
index 41ef503..f2dffd8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,6 +30,7 @@ MODULES =					\
   guix/scripts/import.scm			\
   guix/scripts/package.scm			\
   guix/scripts/gc.scm				\
+  guix/scripts/hash.scm				\
   guix/scripts/pull.scm				\
   guix/base32.scm				\
   guix/utils.scm				\
diff --git a/guix/scripts/hash.scm b/guix/scripts/hash.scm
new file mode 100644
index 0000000..4ed04f2
--- /dev/null
+++ b/guix/scripts/hash.scm
@@ -0,0 +1,90 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts hash)
+    #:use-module (guix base32)
+    #:use-module (guix ui)
+    #:use-module (guix utils)
+    #:use-module (rnrs io ports)
+    #:use-module (ice-9 match)
+    #:use-module (srfi srfi-1)
+    #:use-module (srfi srfi-37)
+    #:export (guix-hash))
+
+(define (file->hash file)
+  "Return the cryptographic hash of FILE in Base32."
+  (call-with-input-file file
+    (compose bytevector->nix-base32-string
+             sha256
+             get-bytevector-all)))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  '())
+
+(define (show-help)
+  (display (_ "Usage: guix hash FILE
+Return the cryptographic hash of FILE in Base32.\n"))
+  (display (_ "
+  -h, --help             display this help and exit"))
+  (display (_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specification of the command-line options.
+  (list (option '(#\h "help") #f #f
+                (lambda args
+                  (show-help)
+                  (exit 0)))
+        (option '(#\V "version") #f #f
+                (lambda args
+                  (show-version-and-exit "guix hash")))))
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-hash . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold args %options
+               (lambda (opt name arg result)
+                 (leave (_ "~A: unrecognized option~%") name))
+               (lambda (arg result)
+                 (alist-cons 'argument arg result))
+               %default-options))
+
+  (let* ((opts (parse-options))
+         (args (filter-map (match-lambda
+                            (('argument . value)
+                             value)
+                            (_ #f))
+                           (reverse opts))))
+    (match args
+      ((file)
+       (format #t "~a~%" (file->hash file)))
+
+      (_
+       (leave (_ "wrong number of arguments~%"))))))
-- 
1.7.5.4


[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-01  5:06 [PATCH] Add 'guix hash' Nikita Karetnikov
@ 2013-04-03  8:34 ` Ludovic Courtès
  2013-04-05 14:04   ` Nikita Karetnikov
  0 siblings, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-03  8:34 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

> This patch adds a 'guix hash' command.

Nice!

> I'd like it to output non-Base32 too, but I haven't found a way to
> convert the output of 'sha256', which is a bytevector, to a string.

You mean a hexadecimal string?  There’s bytevector->base16-string in
(guix utils).

> What options would you like to see implemented?

Could you copy/paste the --format option found in (guix scripts download)?

> Should we capitalize error messages?

No (info "(standards) Errors"):

     The string MESSAGE should not begin with a capital letter when it
  follows a program name and/or file name, because that isn't the
  beginning of a sentence.  (The sentence conceptually starts at the
  beginning of the line.)  Also, it should not end with a period.

     Error messages from interactive programs, and other messages such as
  usage messages, should start with a capital letter.  But they should not
  end with a period.

> Is it OK to output a backtrace when the specified file doesn't exist?

No, because it’s too scaring.  :-)

I’m sure there are still places where the guix commands spit out a
backtrace, but we should fix that.

> +  "Return the cryptographic hash of FILE in Base32."

“base32” (lower-case).

Also, could you add an entry in the manual (with a couple of sentences
explaining when users should care about this tool, and what it does), as
well as a line in po/POTFILES.in?

Thanks,
Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-03  8:34 ` Ludovic Courtès
@ 2013-04-05 14:04   ` Nikita Karetnikov
  2013-04-05 14:14     ` Nikita Karetnikov
  2013-04-05 16:13     ` Ludovic Courtès
  0 siblings, 2 replies; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-05 14:04 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix


[-- Attachment #1.1: Type: text/plain, Size: 1181 bytes --]

> Could you copy/paste the --format option found in (guix scripts
> download)?

I changed it a bit.

(By the way, I'd like to add your copyright to the header of 'hash.scm'.
What year should be used?)

>> Should we capitalize error messages?

> No (info "(standards) Errors"): [...]

OK, I prepended 'guix hash' to all messages.  I'd like to change other
commands (e.g., 'guix download') accordingly.  What do you think?

I also want to change the output of 'guix download --help'.  In
particular, I'd like to specify the supported formats and remove
(default: `nix-base32').  Basically, I want it to look like the output
of 'guix hash --help'.

>> Is it OK to output a backtrace when the specified file doesn't exist?

> No, because it’s too scaring.  :-)

Done.

> Also, could you add an entry in the manual (with a couple of sentences
> explaining when users should care about this tool, and what it does), as
> well as a line in po/POTFILES.in?

Done.  But what is a translatable string?  Is it a string that should be
i18n'd?

Do you have any suggestions regarding the manual entry of 'guix hash'?
The current version looks rough to me.


[-- Attachment #1.2: 0001-Add-guix-hash.patch --]
[-- Type: text/x-diff, Size: 7306 bytes --]

From 4e36644099b71057d01fe3299036c06204ddd326 Mon Sep 17 00:00:00 2001
From: Nikita Karetnikov <nikita@karetnikov.org>
Date: Fri, 5 Apr 2013 13:10:25 +0000
Subject: [PATCH] Add 'guix hash'.

* guix/scripts/hash.scm: New file.
* Makefile.am (MODULES): Add it.
* po/POTFILES.in: Add it.
* doc/guix.texi (Invoking guix hash): New node.
---
 Makefile.am           |    1 +
 doc/guix.texi         |   37 +++++++++++++++
 guix/scripts/hash.scm |  118 +++++++++++++++++++++++++++++++++++++++++++++++++
 po/POTFILES.in        |    1 +
 4 files changed, 157 insertions(+), 0 deletions(-)
 create mode 100644 guix/scripts/hash.scm

diff --git a/Makefile.am b/Makefile.am
index 136c01b..eb8b80f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,6 +30,7 @@ MODULES =					\
   guix/scripts/import.scm			\
   guix/scripts/package.scm			\
   guix/scripts/gc.scm				\
+  guix/scripts/hash.scm				\
   guix/scripts/pull.scm				\
   guix/scripts/substitute-binary.scm		\
   guix/base32.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 1be172c..b24a92e 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -1087,6 +1087,7 @@ space.
 
 @menu
 * Invoking guix build:: Building packages from the command line.
+* Invoking guix hash:: Computing the cryptographic hash of a file.
 @end menu
 
 @node Invoking guix build
@@ -1182,6 +1183,42 @@ the @code{package-derivation} procedure of the @code{(guix packages)}
 module, and to the @code{build-derivations} procedure of the @code{(guix
 store)} module.
 
+@node Invoking guix hash
+@section Invoking @command{guix hash}
+
+The @command{guix hash} command computes the cryptographic hash of a
+file.
+
+The general syntax is:
+
+@example
+guix hash @var{option} @var{file}
+@end example
+
+@command{guix hash} has the following option:
+
+@table @code
+
+@item --format=@var{fmt}
+@itemx -f @var{fmt}
+Write the hash in the given format.
+
+Supported formats: @code{nix-base32}, @code{base32}, @code{base16}
+(@code{hex} and @code{hexadecimal} can be used as well).
+
+If the @option{--format} option is not specified, @command{guix hash}
+will output the hash in @code{nix-base32}.  This representation is used
+in the definitions of packages.
+
+@end table
+
+@command{guix hash} is a convenient tool to check the integrity of a
+file.  For example, it can be used to compute the hashes of bootstrap
+binaries.
+
+There is also @code{guix download} which computes the hash of a remote
+file.
+
 @c *********************************************************************
 @node GNU Distribution
 @chapter GNU Distribution
diff --git a/guix/scripts/hash.scm b/guix/scripts/hash.scm
new file mode 100644
index 0000000..424f3b9
--- /dev/null
+++ b/guix/scripts/hash.scm
@@ -0,0 +1,118 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts hash)
+    #:use-module (guix base32)
+    #:use-module (guix ui)
+    #:use-module (guix utils)
+    #:use-module (rnrs io ports)
+    #:use-module (rnrs files)
+    #:use-module (ice-9 match)
+    #:use-module (srfi srfi-1)
+    #:use-module (srfi srfi-26)
+    #:use-module (srfi srfi-37)
+    #:export (guix-hash))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  ;; Alist of default option values.
+  `((format . ,bytevector->nix-base32-string)))
+
+(define (show-help)
+  (display (_ "Usage: guix hash [OPTION] FILE
+Return the cryptographic hash of FILE.
+
+Supported formats: 'nix-base32' (default), 'base32', and 'base16'
+('hex' and 'hexadecimal' can be used as well).\n"))
+  (format #t (_ "
+  -f, --format=FMT       write the hash in the given format"))
+  (newline)
+  (display (_ "
+  -h, --help             display this help and exit"))
+  (display (_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specification of the command-line options.
+  (list (option '(#\f "format") #t #f
+                (lambda (opt name arg result)
+                  (define fmt-proc
+                    (match arg
+                      ("nix-base32"
+                       bytevector->nix-base32-string)
+                      ("base32"
+                       bytevector->base32-string)
+                      ((or "base16" "hex" "hexadecimal")
+                       bytevector->base16-string)
+                      (x
+                       (leave (_ "~a: unsupported hash format: ~a~%")
+                              "guix hash" arg))))
+
+                  (alist-cons 'format fmt-proc
+                              (alist-delete 'format result))))
+
+        (option '(#\h "help") #f #f
+                (lambda args
+                  (show-help)
+                  (exit 0)))
+        (option '(#\V "version") #f #f
+                (lambda args
+                  (show-version-and-exit "guix hash")))))
+
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-hash . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold args %options
+               (lambda (opt name arg result)
+                 (leave (_ "~a: unrecognized option: ~a~%")
+                        "guix hash" name))
+               (lambda (arg result)
+                 (alist-cons 'argument arg result))
+               %default-options))
+
+    (let* ((opts (parse-options))
+           (args (filter-map (match-lambda
+                              (('argument . value)
+                               value)
+                              (_ #f))
+                             (reverse opts)))
+           (fmt  (assq-ref opts 'format)))
+
+      (match args
+        ((file)
+         (if (file-exists? file)
+             (format #t "~a~%"
+                     (call-with-input-file file
+                       (compose fmt sha256 get-bytevector-all)))
+             (leave (_ "~a: file '~a' does not exist~%")
+                    "guix hash" (basename file))))
+        (_
+         (leave (_ "~a: wrong number of arguments~%")
+                "guix hash")))))
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bdb894d..3c712a4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,5 +8,6 @@ guix/scripts/build.scm
 guix/scripts/download.scm
 guix/scripts/package.scm
 guix/scripts/gc.scm
+guix/scripts/hash.scm
 guix/scripts/pull.scm
 guix/ui.scm
-- 
1.7.5.4


[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-05 14:04   ` Nikita Karetnikov
@ 2013-04-05 14:14     ` Nikita Karetnikov
  2013-04-05 16:15       ` Ludovic Courtès
  2013-04-05 16:13     ` Ludovic Courtès
  1 sibling, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-05 14:14 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 296 bytes --]

> +         (if (file-exists? file)
> +             (format #t "~a~%"
> +                     (call-with-input-file file
> +                       (compose fmt sha256 get-bytevector-all)))

Oh, Mark warned me about 'file-exists?' some time ago.

How can I do the same but avoid a race condition?

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-05 14:04   ` Nikita Karetnikov
  2013-04-05 14:14     ` Nikita Karetnikov
@ 2013-04-05 16:13     ` Ludovic Courtès
  2013-04-09 16:28       ` Nikita Karetnikov
                         ` (2 more replies)
  1 sibling, 3 replies; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-05 16:13 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>> Could you copy/paste the --format option found in (guix scripts
>> download)?
>
> I changed it a bit.
>
> (By the way, I'd like to add your copyright to the header of 'hash.scm'.
> What year should be used?)

2012, 2013

>>> Should we capitalize error messages?
>
>> No (info "(standards) Errors"): [...]
>
> OK, I prepended 'guix hash' to all messages.  I'd like to change other
> commands (e.g., 'guix download') accordingly.  What do you think?

I think it’d be nice to have a ‘warning’ procedure in (guix ui), so
things are uniform.  Furthermore, ‘guix-main’ could do:

  (parameterize ((current-script-name arg0))
    ...)

so that ‘warning’ and similar procedures could pick up the program name
from there.

Would you like to work on this, in a separate patch?

> I also want to change the output of 'guix download --help'.  In
> particular, I'd like to specify the supported formats and remove
> (default: `nix-base32').  Basically, I want it to look like the output
> of 'guix hash --help'.

I was thinking that it might be enough to list the supported formats in
the manual, and not in --help, which should remain concise.  WDYT?

>> Also, could you add an entry in the manual (with a couple of sentences
>> explaining when users should care about this tool, and what it does), as
>> well as a line in po/POTFILES.in?
>
> Done.  But what is a translatable string?  Is it a string that should be
> i18n'd?

Yes, introduced by a call to the ‘gettext’ procedure, of which ‘_’ is an alias.

> +@node Invoking guix hash
> +@section Invoking @command{guix hash}
> +
> +The @command{guix hash} command computes the cryptographic hash of a
> +file.

I would add something like: “It is primarily a convenience tool for
anyone contributing to the distribution: it reports the hash of a file,
as appears package definitions (@pxref{Defining Packages}).”

You could add an xref from “Defining Packages” too.

> +@command{guix hash} is a convenient tool to check the integrity of a
> +file.  For example, it can be used to compute the hashes of bootstrap
> +binaries.

I would remove this paragraph.

> +There is also @code{guix download} which computes the hash of a remote
> +file.

I’d remove this sentence, and instead we should add a node for
guix download too (patch welcome! :-)).

Modulo these minor details, it looks good to me.

Thanks!

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-05 14:14     ` Nikita Karetnikov
@ 2013-04-05 16:15       ` Ludovic Courtès
  2013-04-10 11:48         ` Nikita Karetnikov
  0 siblings, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-05 16:15 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>> +         (if (file-exists? file)
>> +             (format #t "~a~%"
>> +                     (call-with-input-file file
>> +                       (compose fmt sha256 get-bytevector-all)))
>
> Oh, Mark warned me about 'file-exists?' some time ago.
>
> How can I do the same but avoid a race condition?

Ah, TOCTTOU, right.

You could do:

  (let ((hash (catch 'system-error
                (lambda ()
                  (call-with-input-file ...))
                (lambda args
                  (leave (_ "error ..." (strerror (system-error-errno args))))))))
    ...)

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-05 16:13     ` Ludovic Courtès
@ 2013-04-09 16:28       ` Nikita Karetnikov
  2013-04-11 20:35         ` Ludovic Courtès
  2013-04-18  5:01       ` Enhanced 'warning' (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
  2013-04-21 18:14       ` [PATCH] Add 'guix hash' Nikita Karetnikov
  2 siblings, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-09 16:28 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 2035 bytes --]

> I think it’d be nice to have a ‘warning’ procedure in (guix ui), so
> things are uniform.  Furthermore, ‘guix-main’ could do:

>   (parameterize ((current-script-name arg0))
>     ...)

> so that ‘warning’ and similar procedures could pick up the program
> name from there.

Not sure how to do it.  How can I get the result of 'guix-main' from a
relevant script (e.g., 'guix/scripts/hash.scm')?

I assume that 'parameterize' should be placed inside 'guix-main'.  But
how can 'warning' access its internals?  Note that I'm new to
'parameterize' and I'm not really comfortable with it.  (Yep, I've read
the manual.)

> Would you like to work on this, in a separate patch?

Yes, I'd like to push it prior to 'guix hash'.  But it seems that you'll
do all the work if you answer my questions.  So feel free to push if the
patch is just a couple of lines.

> I was thinking that it might be enough to list the supported formats
> in the manual, and not in --help, which should remain concise.  WDYT?

Of course, it should be concise but also helpful.  I was puzzled when I
saw it for the first time.  So I still think that we should mention the
formats in the output of '--help'.  I'll create a patch for
'guix download' if you agree.

>>> Also, could you add an entry in the manual (with a couple of
>>> sentences explaining when users should care about this tool, and
>>> what it does), as well as a line in po/POTFILES.in?

>> Done.  But what is a translatable string?  Is it a string that should
>> be i18n'd?

> Yes, introduced by a call to the ‘gettext’ procedure, of which ‘_’ is
> an alias.

Why should we keep track of such files?

Also, what is the purpose of 'let' in 'guix-main'?  If I get it right,
it's used to isolate some functions [1].  But 'option?' is not a
top-level function.  So why bother?  (I expect it's not that easy.)

A similar approach is used in 'scripts/guix'.

[1] https://gnu.org/software/guile/manual/guile.html#Internal-Definitions

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-05 16:15       ` Ludovic Courtès
@ 2013-04-10 11:48         ` Nikita Karetnikov
  2013-04-10 11:54           ` Ludovic Courtès
  0 siblings, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-10 11:48 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 948 bytes --]

> Ah, TOCTTOU, right.

> You could do:

>   (let ((hash (catch 'system-error
>                 (lambda ()
>                   (call-with-input-file ...))
>                 (lambda args
>                   (leave (_ "error ..." (strerror (system-error-errno args))))))))
>     ...)

Here is what I did (I'll remove "guix hash" when we have "warning"):

      (match args
        ((file)
         (catch 'system-error
           (lambda ()
             (format #t "~a~%"
                     (call-with-input-file file
                       (compose fmt sha256 get-bytevector-all))))
           (lambda args
             (leave (_ "~a: ~a~%")
                    "guix hash" (strerror (system-error-errno args))))))
        (_
         (leave (_ "~a: wrong number of arguments~%")
                "guix hash")))))

I guess that "wrong number of arguments" can be handled by
(lambda args ...).  Still, the above feels much safer.

What do you think?

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-10 11:48         ` Nikita Karetnikov
@ 2013-04-10 11:54           ` Ludovic Courtès
  2013-04-10 12:21             ` Nikita Karetnikov
  0 siblings, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-10 11:54 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>> Ah, TOCTTOU, right.
>
>> You could do:
>
>>   (let ((hash (catch 'system-error
>>                 (lambda ()
>>                   (call-with-input-file ...))
>>                 (lambda args
>>                   (leave (_ "error ..." (strerror (system-error-errno args))))))))
>>     ...)
>
> Here is what I did (I'll remove "guix hash" when we have "warning"):
>
>       (match args
>         ((file)
>          (catch 'system-error
>            (lambda ()
>              (format #t "~a~%"
>                      (call-with-input-file file
>                        (compose fmt sha256 get-bytevector-all))))
>            (lambda args
>              (leave (_ "~a: ~a~%")
>                     "guix hash" (strerror (system-error-errno args))))))
>         (_
>          (leave (_ "~a: wrong number of arguments~%")
>                 "guix hash")))))

Looks good.

> I guess that "wrong number of arguments" can be handled by
> (lambda args ...).  Still, the above feels much safer.

Not sure what you mean, but the above snippet is OK.

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-10 11:54           ` Ludovic Courtès
@ 2013-04-10 12:21             ` Nikita Karetnikov
  2013-04-10 17:30               ` Ludovic Courtès
  0 siblings, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-10 12:21 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 437 bytes --]

>> I guess that "wrong number of arguments" can be handled by
>> (lambda args ...).  Still, the above feels much safer.

> Not sure what you mean, but the above snippet is OK.

I thought that it's possible to remove 'match' and get the "wrong number
of arguments" from (strerror ...).  But now I'm not sure.  "wrong number
of arguments" should be handled by 'wrong-number-of-args', not
'system-error'.  So I'll use the proposed version.

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-10 12:21             ` Nikita Karetnikov
@ 2013-04-10 17:30               ` Ludovic Courtès
  0 siblings, 0 replies; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-10 17:30 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>>> I guess that "wrong number of arguments" can be handled by
>>> (lambda args ...).  Still, the above feels much safer.
>
>> Not sure what you mean, but the above snippet is OK.
>
> I thought that it's possible to remove 'match' and get the "wrong number
> of arguments" from (strerror ...).  But now I'm not sure.  "wrong number
> of arguments" should be handled by 'wrong-number-of-args', not
> 'system-error'.  So I'll use the proposed version.

Exactly.  ‘strerror’ is equivalent to the same-named C function–that
is, it returns the error string corresponding to the given errno value.

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-09 16:28       ` Nikita Karetnikov
@ 2013-04-11 20:35         ` Ludovic Courtès
  2013-04-12  5:24           ` master: FAIL: tests/guix-package.sh (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
  0 siblings, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-11 20:35 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>> I think it’d be nice to have a ‘warning’ procedure in (guix ui), so
>> things are uniform.  Furthermore, ‘guix-main’ could do:
>
>>   (parameterize ((current-script-name arg0))
>>     ...)
>
>> so that ‘warning’ and similar procedures could pick up the program
>> name from there.
>
> Not sure how to do it.  How can I get the result of 'guix-main' from a
> relevant script (e.g., 'guix/scripts/hash.scm')?
>
> I assume that 'parameterize' should be placed inside 'guix-main'.  But
> how can 'warning' access its internals?  Note that I'm new to
> 'parameterize' and I'm not really comfortable with it.  (Yep, I've read
> the manual.)

‘parameterize’ sets dynamically-scoped variables (or “parameters”, in
SRFI-39 terms).  So for instance:

  (let* ((p (make-parameter 'outside))
         (f (lambda () (format #f "i am ~a" (p)))))
    (parameterize ((p 'inside))
      (f)))

  ⇒ "i am inside"

It’s like ‘current-input-port’ & co.

>> Would you like to work on this, in a separate patch?
>
> Yes, I'd like to push it prior to 'guix hash'.  But it seems that you'll
> do all the work if you answer my questions.  So feel free to push if the
> patch is just a couple of lines.

OK, done.

>> I was thinking that it might be enough to list the supported formats
>> in the manual, and not in --help, which should remain concise.  WDYT?
>
> Of course, it should be concise but also helpful.  I was puzzled when I
> saw it for the first time.  So I still think that we should mention the
> formats in the output of '--help'.  I'll create a patch for
> 'guix download' if you agree.

OK.

>>>> Also, could you add an entry in the manual (with a couple of
>>>> sentences explaining when users should care about this tool, and
>>>> what it does), as well as a line in po/POTFILES.in?
>
>>> Done.  But what is a translatable string?  Is it a string that should
>>> be i18n'd?
>
>> Yes, introduced by a call to the ‘gettext’ procedure, of which ‘_’ is
>> an alias.
>
> Why should we keep track of such files?

Because ‘xgettext’ extracts translatable strings from files listed
therein (info "(gettext) po/POTFILES.in").

> Also, what is the purpose of 'let' in 'guix-main'?  If I get it right,
> it's used to isolate some functions [1].  But 'option?' is not a
> top-level function.  So why bother?  (I expect it's not that easy.)

Yeah, I’d have written:

  (define (guix-main ...)
    (define (option? x) ...)
    (initialize-guix)
    (match args ...))

But it’s basically equivalent.

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* master: FAIL: tests/guix-package.sh (was: [PATCH] Add 'guix hash'.)
  2013-04-11 20:35         ` Ludovic Courtès
@ 2013-04-12  5:24           ` Nikita Karetnikov
  2013-04-12  6:48             ` master: FAIL: tests/guix-package.sh Nikita Karetnikov
  2013-04-12 16:24             ` Ludovic Courtès
  0 siblings, 2 replies; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-12  5:24 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 621 bytes --]

>>> Would you like to work on this, in a separate patch?
>>
>> Yes, I'd like to push it prior to 'guix hash'.  But it seems that you'll
>> do all the work if you answer my questions.  So feel free to push if the
>> patch is just a couple of lines.

> OK, done.

'make check' returns "FAIL: tests/guix-package.sh" on master.

I believe this commit [1] is the cause of the problem.  Everything works
if I switch to the previous commit.

I think that it's only necessary to adjust '_' in 'package.scm'.  I'm
trying to do so.

[1] http://git.savannah.gnu.org/cgit/guix.git/commit/?id=a2011be5dfaf2b94a1d0e3dfbcf4b512389b4711

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: master: FAIL: tests/guix-package.sh
  2013-04-12  5:24           ` master: FAIL: tests/guix-package.sh (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
@ 2013-04-12  6:48             ` Nikita Karetnikov
  2013-04-12 16:24             ` Ludovic Courtès
  1 sibling, 0 replies; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-12  6:48 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 221 bytes --]

> I think that it's only necessary to adjust '_' in 'package.scm'.  I'm
> trying to do so.

Hmmm, I've tried to replace (format (current-error-port) ...) with
'leave' or 'warning', but it still fails.  Could anyone help?

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: master: FAIL: tests/guix-package.sh
  2013-04-12  5:24           ` master: FAIL: tests/guix-package.sh (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
  2013-04-12  6:48             ` master: FAIL: tests/guix-package.sh Nikita Karetnikov
@ 2013-04-12 16:24             ` Ludovic Courtès
  1 sibling, 0 replies; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-12 16:24 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

> 'make check' returns "FAIL: tests/guix-package.sh" on master.
>
> I believe this commit [1] is the cause of the problem.  Everything works
> if I switch to the previous commit.

Oops, indeed.  Fixed in c31d1a7.

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Enhanced 'warning' (was: [PATCH] Add 'guix hash'.)
  2013-04-05 16:13     ` Ludovic Courtès
  2013-04-09 16:28       ` Nikita Karetnikov
@ 2013-04-18  5:01       ` Nikita Karetnikov
  2013-04-18  5:06         ` Enhanced 'warning' Nikita Karetnikov
  2013-04-18 11:55         ` Ludovic Courtès
  2013-04-21 18:14       ` [PATCH] Add 'guix hash' Nikita Karetnikov
  2 siblings, 2 replies; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-18  5:01 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 1367 bytes --]

> I think it’d be nice to have a ‘warning’ procedure in (guix ui), so
> things are uniform.

It think it might be better to have a single 'warning' macro which could
handle several cases (errors, warnings and similar things).  (Actually,
'guix hash' should use errors, not warnings.)

Here is a simplified version:

(define-syntax define-output-macro
  (syntax-rules ()
    ((_ name prefix)
     (define-syntax name
       (lambda (x)
         (syntax-case x (_ N_)
           ((name (_ str))
            (with-syntax ((prefix (datum->syntax x prefix)))
              #'(display (string-append prefix str "\n"))))
           ((name (N_ str1 str2))
            (with-syntax ((prefix (datum->syntax x prefix)))
              #'(display (string-append prefix str1 str2 "\n"))))))))))

;; (Is there a way not to repeat 'with-syntax'?)

(define-output-macro warning "warning: ")
(define-output-macro error* "error: ")

scheme@(guile-user)> (warning (_ "foo"))
warning: foo

scheme@(guile-user)> (error* (N_ "foo" "bar"))
error: foobar

And here is a problem...  Is it possible to compose a macro (e.g.,
'error*') with (exit 1) without touching the internals of
'define-output-macro'?

Here is an example with a function:

(define (error**)
  (display "Error!\n"))

(define (error-n-exit)
  (begin
	(error**)
	(exit 1)))

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Enhanced 'warning'
  2013-04-18  5:01       ` Enhanced 'warning' (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
@ 2013-04-18  5:06         ` Nikita Karetnikov
  2013-04-18 11:55         ` Ludovic Courtès
  1 sibling, 0 replies; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-18  5:06 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 208 bytes --]

> It think it might be better to have a single 'warning' macro which could
> handle several cases (errors, warnings and similar things).

I meant: "a single macro which could be used to create other macros."

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Enhanced 'warning'
  2013-04-18  5:01       ` Enhanced 'warning' (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
  2013-04-18  5:06         ` Enhanced 'warning' Nikita Karetnikov
@ 2013-04-18 11:55         ` Ludovic Courtès
  2013-04-18 19:27           ` Nikita Karetnikov
  1 sibling, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-18 11:55 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>> I think it’d be nice to have a ‘warning’ procedure in (guix ui), so
>> things are uniform.
>
> It think it might be better to have a single 'warning' macro which could
> handle several cases (errors, warnings and similar things).  (Actually,
> 'guix hash' should use errors, not warnings.)

Yes, you’re right.

> Here is a simplified version:
>
> (define-syntax define-output-macro

Rather: ‘define-diagnostic’.

>   (syntax-rules ()
>     ((_ name prefix)
>      (define-syntax name
>        (lambda (x)
>          (syntax-case x (_ N_)
>            ((name (_ str))
>             (with-syntax ((prefix (datum->syntax x prefix)))
>               #'(display (string-append prefix str "\n"))))
>            ((name (N_ str1 str2))
>             (with-syntax ((prefix (datum->syntax x prefix)))
>               #'(display (string-append prefix str1 str2 "\n"))))))))))

You should reuse the body of the current ‘warning’ macro, though.

> (define-output-macro warning "warning: ")
> (define-output-macro error* "error: ")

You could use ‘report-error’ to avoid name clashes.

But I think ‘leave’ should be enough, no?

> scheme@(guile-user)> (warning (_ "foo"))
> warning: foo
>
> scheme@(guile-user)> (error* (N_ "foo" "bar"))
> error: foobar

Note that ‘N_’ is meant to be an alias for ‘ngettext’, so the above form
is invalid.

> And here is a problem...  Is it possible to compose a macro (e.g.,
> 'error*') with (exit 1) without touching the internals of
> 'define-output-macro'?

What about:

  (define-syntax-rule (leave args ...)
    (begin
      (error* args ...)
      (exit 1)))

Thanks,
Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Enhanced 'warning'
  2013-04-18 11:55         ` Ludovic Courtès
@ 2013-04-18 19:27           ` Nikita Karetnikov
  2013-04-18 20:59             ` Ludovic Courtès
  0 siblings, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-18 19:27 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 1446 bytes --]

> You should reuse the body of the current ‘warning’ macro, though.

What's wrong with this macro?

(define-syntax define-diagnostic
  (syntax-rules ()
    ((define-diagnostic name prefix)
     (define-syntax name
       (lambda (x)
         (define (augmented-format-string fmt)
           (string-append "~:[~*~;guix ~a: ~]~a" (syntax->datum fmt)))

         (syntax-case x (N_ _)                    ; these are literals, yeah...
           ((name (_ fmt) args ...)
            (string? (syntax->datum #'fmt))
            (with-syntax ((fmt*   (augmented-format-string #'fmt))
                          (prefix (datum->syntax x prefix)))
              #'(format (guix-warning-port) (gettext fmt*)
                        (program-name) (program-name) prefix
                        args ...)))
           ((name (N_ singular plural n) args ...)
            (and (string? (syntax->datum #'singular))
                 (string? (syntax->datum #'plural)))
            (with-syntax ((s      (augmented-format-string #'singular))
                          (p      (augmented-format-string #'plural))
                          (prefix (datum->syntax x prefix)))
              #'(format (guix-warning-port)
                        (ngettext s p n %gettext-domain)
                        (program-name) (program-name) prefix
                        args ...)))))))))

I'm getting the "extra ellipsis in form" error.

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Enhanced 'warning'
  2013-04-18 19:27           ` Nikita Karetnikov
@ 2013-04-18 20:59             ` Ludovic Courtès
  2013-04-19 20:16               ` [PATCH] ui: Add a 'define-diagnostic' macro. (was: Enhanced 'warning') Nikita Karetnikov
  0 siblings, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-18 20:59 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>> You should reuse the body of the current ‘warning’ macro, though.
>
> What's wrong with this macro?
>
> (define-syntax define-diagnostic
>   (syntax-rules ()
>     ((define-diagnostic name prefix)

Since there’s a single rule, you should use ‘define-syntax-rule’
instead, for conciseness.

>      (define-syntax name
>        (lambda (x)
>          (define (augmented-format-string fmt)
>            (string-append "~:[~*~;guix ~a: ~]~a" (syntax->datum fmt)))
>
>          (syntax-case x (N_ _)                    ; these are literals, yeah...
>            ((name (_ fmt) args ...)
>             (string? (syntax->datum #'fmt))
>             (with-syntax ((fmt*   (augmented-format-string #'fmt))
>                           (prefix (datum->syntax x prefix)))
>               #'(format (guix-warning-port) (gettext fmt*)
>                         (program-name) (program-name) prefix
>                         args ...)))
>            ((name (N_ singular plural n) args ...)
>             (and (string? (syntax->datum #'singular))
>                  (string? (syntax->datum #'plural)))
>             (with-syntax ((s      (augmented-format-string #'singular))
>                           (p      (augmented-format-string #'plural))
>                           (prefix (datum->syntax x prefix)))
>               #'(format (guix-warning-port)
>                         (ngettext s p n %gettext-domain)
>                         (program-name) (program-name) prefix
>                         args ...)))))))))
>
> I'm getting the "extra ellipsis in form" error.

This is a macro-generating macro.  In the body of the generated macro,
above, there are 4 occurrences of ‘...’.  But these ellipses have no
meaning in the outer macro; they are just meaningful in the context of
the generated macro, hence the error.

Instead, you should replace all 4 occurrences with (... ...).

Yes, it’s always surprising at first.  ;-)

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH] ui: Add a 'define-diagnostic' macro. (was: Enhanced 'warning')
  2013-04-18 20:59             ` Ludovic Courtès
@ 2013-04-19 20:16               ` Nikita Karetnikov
  2013-04-20  5:48                 ` [PATCH] ui: Add a 'define-diagnostic' macro Nikita Karetnikov
  2013-04-20  9:09                 ` Ludovic Courtès
  0 siblings, 2 replies; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-19 20:16 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix


[-- Attachment #1.1: Type: text/plain, Size: 1020 bytes --]

> This is a macro-generating macro.  In the body of the generated macro,
> above, there are 4 occurrences of ‘...’.  But these ellipses have no
> meaning in the outer macro; they are just meaningful in the context of
> the generated macro, hence the error.

> Instead, you should replace all 4 occurrences with (... ...).

> Yes, it’s always surprising at first.  ;-)

Yep, could you add it to the manual?  There is only a reference to this
book [1] which briefly discusses the topic.

I'm attaching the patch that adds a 'define-diagnostic' macro.  Can I
push it to 'master'?

I ran 'grep' to find things which use "warning" or "leave."  I guess
it's possible to change other functions (the ones that use 'error' and
'format').  But it will probably trigger a rebuild.  So what should I
do?

Also, is it possible to move 'report-error' inside 'leave'?

Finally, I haven't tested each change.  All tests pass and there are no
warnings.  Is it good enough?

[1] http://scheme.com/tspl4/


[-- Attachment #1.2: 0001-ui-Add-a-define-diagnostic-macro.patch --]
[-- Type: text/x-diff, Size: 14218 bytes --]

From 9f5d9501a270bd64c563e41f57278aba42266364 Mon Sep 17 00:00:00 2001
From: Nikita Karetnikov <nikita@karetnikov.org>
Date: Fri, 19 Apr 2013 19:17:41 +0000
Subject: [PATCH] ui: Add a 'define-diagnostic' macro.

* guix/ui.scm (define-diagnostic): New macro, which is based on the
  previous version of 'warning'.
  (warning, leave): Redefine using 'define-diagnostic'.
  (report-error): New macro.
  (install-locale): Use 'warning' instead of 'format'.
  (call-with-error-handling): Adjust 'leave'.
* gnu/packages.scm (package-files): Use 'warning' instead of 'format'.
* guix/gnu-maintenance.scm (http-fetch): Use 'warning' and 'leave'.
* guix/scripts/build.scm (derivations-from-package-expressions, guix-build):
  Adjust 'leave'.
* guix/scripts/download.scm (guix-download): Adjust 'leave'.
* guix/scripts/gc.scm (size->number, %options): Adjust 'leave'.
* guix/scripts/package.scm (roll-back, guix-package): Adjust 'leave'.
---
 gnu/packages.scm          |    6 ++--
 guix/gnu-maintenance.scm  |   12 +++---
 guix/scripts/build.scm    |   14 ++++----
 guix/scripts/download.scm |    4 +-
 guix/scripts/gc.scm       |    7 ++--
 guix/scripts/package.scm  |    5 +--
 guix/ui.scm               |   82 ++++++++++++++++++++++----------------------
 7 files changed, 64 insertions(+), 66 deletions(-)

diff --git a/gnu/packages.scm b/gnu/packages.scm
index f4d93a7..e9f2540 100644
--- a/gnu/packages.scm
+++ b/gnu/packages.scm
@@ -19,6 +19,7 @@
 
 (define-module (gnu packages)
   #:use-module (guix packages)
+  #:use-module (guix ui)
   #:use-module (guix utils)
   #:use-module (ice-9 ftw)
   #:use-module (ice-9 vlist)
@@ -90,9 +91,8 @@
                       result)
                     (const #f)                    ; skip
                     (lambda (path stat errno result)
-                      (format (current-error-port)
-                              (_ "warning: cannot access `~a': ~a~%")
-                              path (strerror errno))
+                      (warning (_ "cannot access `~a': ~a~%")
+                               path (strerror errno))
                       result)
                     '()
                     %distro-module-directory
diff --git a/guix/gnu-maintenance.scm b/guix/gnu-maintenance.scm
index 89e7f25..5df9c6f 100644
--- a/guix/gnu-maintenance.scm
+++ b/guix/gnu-maintenance.scm
@@ -29,6 +29,7 @@
   #:use-module (srfi srfi-26)
   #:use-module (system foreign)
   #:use-module (guix ftp-client)
+  #:use-module (guix ui)
   #:use-module (guix utils)
   #:use-module (guix packages)
   #:export (gnu-package-name
@@ -84,12 +85,11 @@
                 ;; (see <http://lists.gnu.org/archive/html/guile-devel/2011-09/msg00089.html>).
                 ;; Since users may still be using these versions, warn them and
                 ;; bail out.
-                (format (current-error-port)
-                        "warning: using Guile ~a, ~a ~s encoding~%"
-                        (version)
-                        "which does not support HTTP"
-                        (response-transfer-encoding resp))
-                (error "download failed; use a newer Guile"
+                (warning (_ "using Guile ~a, ~a ~s encoding~%")
+                         (version)
+                         "which does not support HTTP"
+                         (response-transfer-encoding resp))
+                (leave (_ "download failed; use a newer Guile")
                        uri resp)))
              ((string? data)                 ; old `http-get' returns a string
               (open-input-string data))
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
index f296f30..0bf154d 100644
--- a/guix/scripts/build.scm
+++ b/guix/scripts/build.scm
@@ -43,12 +43,11 @@
 When SOURCE? is true, return the derivations of the package sources."
   (let ((p (read/eval-package-expression str)))
     (if source?
-        (let ((source (package-source p))
-              (loc    (package-location p)))
+        (let ((source (package-source p)))
           (if source
               (package-source-derivation (%store) source)
-              (leave (_ "~a: error: package `~a' has no source~%")
-                     (location->string loc) (package-name p))))
+              (leave (_ "package `~a' has no source~%")
+                     (package-name p))))
         (package-derivation (%store) p system))))
 
 \f
@@ -169,7 +168,9 @@ Build the given PACKAGE-OR-DERIVATION and return their output paths.\n"))
             (add-indirect-root (%store) root))
            ((paths ...)
             (fold (lambda (path count)
-                    (let ((root (string-append root "-" (number->string count))))
+                    (let ((root (string-append root
+                                               "-"
+                                               (number->string count))))
                       (symlink path root)
                       (add-indirect-root (%store) root))
                     (+ 1 count))
@@ -177,8 +178,7 @@ Build the given PACKAGE-OR-DERIVATION and return their output paths.\n"))
                   paths))))
        (lambda args
          (leave (_ "failed to create GC root `~a': ~a~%")
-                root (strerror (system-error-errno args)))
-         (exit 1)))))
+                root (strerror (system-error-errno args)))))))
 
   (define newest-available-packages
     (memoize find-newest-available-packages))
diff --git a/guix/scripts/download.scm b/guix/scripts/download.scm
index 7c00312..c5c56c5 100644
--- a/guix/scripts/download.scm
+++ b/guix/scripts/download.scm
@@ -114,7 +114,7 @@ and the hash of its contents.\n"))
            (store (open-connection))
            (arg   (assq-ref opts 'argument))
            (uri   (or (string->uri arg)
-                      (leave (_ "guix-download: ~a: failed to parse URI~%")
+                      (leave (_ "~a: failed to parse URI~%")
                              arg)))
            (path  (case (uri-scheme uri)
                     ((file)
@@ -127,7 +127,7 @@ and the hash of its contents.\n"))
                                       (basename (uri-path uri))))))
            (hash  (call-with-input-file
                       (or path
-                          (leave (_ "guix-download: ~a: download failed~%")
+                          (leave (_ "~a: download failed~%")
                                  arg))
                     (compose sha256 get-bytevector-all)))
            (fmt   (assq-ref opts 'format)))
diff --git a/guix/scripts/gc.scm b/guix/scripts/gc.scm
index 3d91892..f464579 100644
--- a/guix/scripts/gc.scm
+++ b/guix/scripts/gc.scm
@@ -87,9 +87,8 @@ interpreted."
              ("TB"  (expt 10 12))
              (""    1)
              (_
-              (leave (_ "error: unknown unit: ~a~%") unit)
-              (exit 1))))
-        (leave (_ "error: invalid number: ~a") numstr))))
+              (leave (_ "unknown unit: ~a~%") unit))))
+        (leave (_ "invalid number: ~a") numstr))))
 
 (define %options
   ;; Specification of the command-line options.
@@ -110,7 +109,7 @@ interpreted."
                       (let ((amount (size->number arg)))
                         (if arg
                             (alist-cons 'min-freed amount result)
-                            (leave (_ "error: invalid amount of storage: ~a~%")
+                            (leave (_ "invalid amount of storage: ~a~%")
                                    arg))))
                      (#f result)))))
         (option '(#\d "delete") #f #f
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 4295aba..c5656ef 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -208,7 +208,7 @@ all of PACKAGES, a list of name/version/output/path/deps tuples."
       (switch-symlinks profile previous-profile))
 
     (cond ((not (file-exists? profile))           ; invalid profile
-           (leave (_ "error: profile `~a' does not exist~%")
+           (leave (_ "profile `~a' does not exist~%")
                   profile))
           ((zero? number)                         ; empty profile
            (format (current-error-port)
@@ -477,8 +477,7 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
     (define (ensure-output p sub-drv)
       (if (member sub-drv (package-outputs p))
           p
-          (leave (_ "~a: error: package `~a' lacks output `~a'~%")
-                 (location->string (package-location p))
+          (leave (_ "package `~a' lacks output `~a'~%")
                  (package-full-name p)
                  sub-drv)))
 
diff --git a/guix/ui.scm b/guix/ui.scm
index 938b5d2..e42c331 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -1,6 +1,7 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
+;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -70,9 +71,8 @@
     (lambda _
       (setlocale LC_ALL ""))
     (lambda args
-      (format (current-error-port)
-              (_ "warning: failed to install locale: ~a~%")
-              (strerror (system-error-errno args))))))
+      (warning (_ "failed to install locale: ~a~%")
+               (strerror (system-error-errno args))))))
 
 (define (initialize-guix)
   "Perform the usual initialization for stand-alone Guix commands."
@@ -81,12 +81,6 @@
   (setvbuf (current-output-port) _IOLBF)
   (setvbuf (current-error-port) _IOLBF))
 
-(define-syntax-rule (leave fmt args ...)
-  "Format FMT and ARGS to the error port and exit."
-  (begin
-    (format (current-error-port) fmt args ...)
-    (exit 1)))
-
 (define* (show-version-and-exit #:optional (command (car (command-line))))
   "Display version information for COMMAND and `(exit 0)'."
   (simple-format #t "~a (~a) ~a~%"
@@ -111,16 +105,16 @@ General help using GNU software: <http://www.gnu.org/gethelp/>"))
                     (file     (location-file location))
                     (line     (location-line location))
                     (column   (location-column location)))
-               (leave (_ "~a:~a:~a: error: package `~a' has an invalid input: ~s~%")
+               (leave (_ "~a:~a:~a: package `~a' has an invalid input: ~s~%")
                       file line column
                       (package-full-name package) input)))
             ((nix-connection-error? c)
-             (leave (_ "error: failed to connect to `~a': ~a~%")
+             (leave (_ "failed to connect to `~a': ~a~%")
                     (nix-connection-error-file c)
                     (strerror (nix-connection-error-code c))))
             ((nix-protocol-error? c)
              ;; FIXME: Server-provided error messages aren't i18n'd.
-             (leave (_ "error: build failed: ~a~%")
+             (leave (_ "build failed: ~a~%")
                     (nix-protocol-error-message c))))
     (thunk)))
 
@@ -375,35 +369,41 @@ WIDTH columns."
 (define guix-warning-port
   (make-parameter (current-warning-port)))
 
-(define-syntax warning
-  (lambda (s)
-    "Emit a warming.  The macro assumes that `_' is bound to `gettext'."
-    ;; All this just to preserve `-Wformat' warnings.  Too much?
-
-    (define (augmented-format-string fmt)
-      (string-append "~:[~*~;guix ~a: ~]~a" (syntax->datum fmt)))
-
-    (define prefix
-      #'(_ "warning: "))
-
-    (syntax-case s (N_ _)                        ; these are literals, yeah...
-      ((warning (_ fmt) args ...)
-       (string? (syntax->datum #'fmt))
-       (with-syntax ((fmt*   (augmented-format-string #'fmt))
-                     (prefix prefix))
-         #'(format (guix-warning-port) (gettext fmt*)
-                   (program-name) (program-name) prefix
-                   args ...)))
-      ((warning (N_ singular plural n) args ...)
-       (and (string? (syntax->datum #'singular))
-            (string? (syntax->datum #'plural)))
-       (with-syntax ((s (augmented-format-string #'singular))
-                     (p (augmented-format-string #'plural))
-                     (b prefix))
-         #'(format (guix-warning-port)
-                   (ngettext s p n %gettext-domain)
-                   (program-name) (program-name) b
-                   args ...))))))
+(define-syntax-rule (define-diagnostic name prefix)
+  "Create a diagnostic macro (i.e., NAME), which will prepend PREFIX to all
+messages."
+  (define-syntax name
+    (lambda (x)
+      (define (augmented-format-string fmt)
+        (string-append "~:[~*~;guix ~a: ~]~a" (syntax->datum fmt)))
+
+      (syntax-case x (N_ _)                    ; these are literals, yeah...
+        ((name (_ fmt) args (... ...))
+         (string? (syntax->datum #'fmt))
+         (with-syntax ((fmt*   (augmented-format-string #'fmt))
+                       (prefix (datum->syntax x prefix)))
+           #'(format (guix-warning-port) (gettext fmt*)
+                     (program-name) (program-name) prefix
+                     args (... ...))))
+        ((name (N_ singular plural n) args (... ...))
+         (and (string? (syntax->datum #'singular))
+              (string? (syntax->datum #'plural)))
+         (with-syntax ((s      (augmented-format-string #'singular))
+                       (p      (augmented-format-string #'plural))
+                       (prefix (datum->syntax x prefix)))
+           #'(format (guix-warning-port)
+                     (ngettext s p n %gettext-domain)
+                     (program-name) (program-name) prefix
+                     args (... ...))))))))
+
+(define-diagnostic warning "warning: ") ; emit a warning
+
+(define-diagnostic report-error "error: ")
+(define-syntax-rule (leave args ...)
+  "Emit an error message and exit."
+  (begin
+    (report-error args ...)
+    (exit 1)))
 
 (define (guix-main arg0 . args)
   (initialize-guix)
-- 
1.7.5.4


[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH] ui: Add a 'define-diagnostic' macro.
  2013-04-19 20:16               ` [PATCH] ui: Add a 'define-diagnostic' macro. (was: Enhanced 'warning') Nikita Karetnikov
@ 2013-04-20  5:48                 ` Nikita Karetnikov
  2013-04-20  9:10                   ` Ludovic Courtès
  2013-04-20  9:09                 ` Ludovic Courtès
  1 sibling, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-20  5:48 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 66 bytes --]

FYI, I forgot to add 'guix/gnu-maintenance.scm' to 'POTFILES.in'.

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] ui: Add a 'define-diagnostic' macro.
  2013-04-19 20:16               ` [PATCH] ui: Add a 'define-diagnostic' macro. (was: Enhanced 'warning') Nikita Karetnikov
  2013-04-20  5:48                 ` [PATCH] ui: Add a 'define-diagnostic' macro Nikita Karetnikov
@ 2013-04-20  9:09                 ` Ludovic Courtès
  1 sibling, 0 replies; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-20  9:09 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>> This is a macro-generating macro.  In the body of the generated macro,
>> above, there are 4 occurrences of ‘...’.  But these ellipses have no
>> meaning in the outer macro; they are just meaningful in the context of
>> the generated macro, hence the error.
>
>> Instead, you should replace all 4 occurrences with (... ...).
>
>> Yes, it’s always surprising at first.  ;-)
>
> Yep, could you add it to the manual?  There is only a reference to this
> book [1] which briefly discusses the topic.

Well, it’s specified in R[56]RS I believe, but yeah.

> I'm attaching the patch that adds a 'define-diagnostic' macro.  Can I
> push it to 'master'?

Looks good to me.  Make sure to run ‘make clean && make’ before, to see
if there’s anything that fails to build (you only need to do this
because these are macros.)

> I ran 'grep' to find things which use "warning" or "leave."  I guess
> it's possible to change other functions (the ones that use 'error' and
> 'format').  But it will probably trigger a rebuild.  So what should I
> do?

Everything in guix/build/* must be left as is: it’s not part of the UI,
except perhaps for (guix build download).  However, the rule is to only
import (guix build ...) modules in (guix build ...) modules.

So this looks fine as is.  We’ll see later if there’s anything wrong
with (guix build download) or something else.

> Also, is it possible to move 'report-error' inside 'leave'?

Didn’t you want to export it as well?  But otherwise no.

> Finally, I haven't tested each change.  All tests pass and there are no
> warnings.  Is it good enough?

Plus ‘make clean && make’.

Please push if it passes that.

Thanks!

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] ui: Add a 'define-diagnostic' macro.
  2013-04-20  5:48                 ` [PATCH] ui: Add a 'define-diagnostic' macro Nikita Karetnikov
@ 2013-04-20  9:10                   ` Ludovic Courtès
  2013-04-20 17:33                     ` Nikita Karetnikov
  0 siblings, 1 reply; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-20  9:10 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

> FYI, I forgot to add 'guix/gnu-maintenance.scm' to 'POTFILES.in'.

It doesn’t use gettext AFAICS, so that’s fine.

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] ui: Add a 'define-diagnostic' macro.
  2013-04-20  9:10                   ` Ludovic Courtès
@ 2013-04-20 17:33                     ` Nikita Karetnikov
  2013-04-20 19:55                       ` Ludovic Courtès
  0 siblings, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-20 17:33 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

>> FYI, I forgot to add 'guix/gnu-maintenance.scm' to 'POTFILES.in'.

> It doesn’t use gettext AFAICS, so that’s fine.

I was talking about this:

+++ b/guix/gnu-maintenance.scm

[...]

+                (warning (_ "using Guile ~a, ~a ~s encoding~%")
+                         (version)
+                         "which does not support HTTP"
+                         (response-transfer-encoding resp))
+                (leave (_ "download failed; use a newer Guile")

I guess it should be added.  Am I mistaken?

[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] ui: Add a 'define-diagnostic' macro.
  2013-04-20 17:33                     ` Nikita Karetnikov
@ 2013-04-20 19:55                       ` Ludovic Courtès
  0 siblings, 0 replies; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-20 19:55 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

>>> FYI, I forgot to add 'guix/gnu-maintenance.scm' to 'POTFILES.in'.
>
>> It doesn’t use gettext AFAICS, so that’s fine.
>
> I was talking about this:
>
> +++ b/guix/gnu-maintenance.scm
>
> [...]
>
> +                (warning (_ "using Guile ~a, ~a ~s encoding~%")
> +                         (version)
> +                         "which does not support HTTP"
> +                         (response-transfer-encoding resp))
> +                (leave (_ "download failed; use a newer Guile")

Ah, OK.

> I guess it should be added.  Am I mistaken?

Then yes, although these messages are not here to stay.

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-05 16:13     ` Ludovic Courtès
  2013-04-09 16:28       ` Nikita Karetnikov
  2013-04-18  5:01       ` Enhanced 'warning' (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
@ 2013-04-21 18:14       ` Nikita Karetnikov
  2013-04-21 19:02         ` Ludovic Courtès
  2 siblings, 1 reply; 28+ messages in thread
From: Nikita Karetnikov @ 2013-04-21 18:14 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: bug-guix


[-- Attachment #1.1: Type: text/plain, Size: 82 bytes --]

> Modulo these minor details, it looks good to me.

OK, can I push this version?


[-- Attachment #1.2: 0001-Add-guix-hash.patch --]
[-- Type: text/x-diff, Size: 8017 bytes --]

From 87eff0719ff0453116d21e89034804806a21b082 Mon Sep 17 00:00:00 2001
From: Nikita Karetnikov <nikita@karetnikov.org>
Date: Sun, 21 Apr 2013 17:20:00 +0000
Subject: [PATCH] Add 'guix hash'.

* guix/scripts/hash.scm: New file.
* Makefile.am (MODULES): Add it.
* po/POTFILES.in: Add it.
* doc/guix.texi (Invoking guix hash): New node.
  (Defining Packages): Add a cross-reference to the 'Invoking guix
  hash' node.
---
 Makefile.am           |    1 +
 doc/guix.texi         |   37 ++++++++++++++-
 guix/scripts/hash.scm |  120 +++++++++++++++++++++++++++++++++++++++++++++++++
 po/POTFILES.in        |    1 +
 4 files changed, 157 insertions(+), 2 deletions(-)
 create mode 100644 guix/scripts/hash.scm

diff --git a/Makefile.am b/Makefile.am
index 3e697a2..d1ae126 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,6 +30,7 @@ MODULES =					\
   guix/scripts/import.scm			\
   guix/scripts/package.scm			\
   guix/scripts/gc.scm				\
+  guix/scripts/hash.scm				\
   guix/scripts/pull.scm				\
   guix/scripts/substitute-binary.scm		\
   guix/base32.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 188ab1a..79c13a1 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -808,8 +808,9 @@ the GNU mirrors defined in @code{(guix download)}.
 The @code{sha256} field specifies the expected SHA256 hash of the file
 being downloaded.  It is mandatory, and allows Guix to check the
 integrity of the file.  The @code{(base32 @dots{})} form introduces the
-base32 representation of the hash.  A convenient way to obtain this
-information is with the @code{guix download} tool.
+base32 representation of the hash.  You can obtain this information with
+the @code{guix hash} (@pxref{Invoking guix hash}) and @code{guix
+download} tools.
 
 @item
 @cindex GNU Build System
@@ -1088,6 +1089,7 @@ space.
 
 @menu
 * Invoking guix build:: Building packages from the command line.
+* Invoking guix hash:: Computing the cryptographic hash of a file.
 @end menu
 
 @node Invoking guix build
@@ -1183,6 +1185,37 @@ the @code{package-derivation} procedure of the @code{(guix packages)}
 module, and to the @code{build-derivations} procedure of the @code{(guix
 store)} module.
 
+@node Invoking guix hash
+@section Invoking @command{guix hash}
+
+The @command{guix hash} command allows to check the integrity of a file.
+It is primarily a convenience tool for anyone contributing to the
+distribution: it computes the cryptographic hash of a file, which can be
+used in the definition of a package (@pxref{Defining Packages}).
+
+The general syntax is:
+
+@example
+guix hash @var{option} @var{file}
+@end example
+
+@command{guix hash} has the following option:
+
+@table @code
+
+@item --format=@var{fmt}
+@itemx -f @var{fmt}
+Write the hash in the given format.
+
+Supported formats: @code{nix-base32}, @code{base32}, @code{base16}
+(@code{hex} and @code{hexadecimal} can be used as well).
+
+If the @option{--format} option is not specified, @command{guix hash}
+will output the hash in @code{nix-base32}.  This representation is used
+in the definitions of packages.
+
+@end table
+
 @c *********************************************************************
 @node GNU Distribution
 @chapter GNU Distribution
diff --git a/guix/scripts/hash.scm b/guix/scripts/hash.scm
new file mode 100644
index 0000000..ad05a4e
--- /dev/null
+++ b/guix/scripts/hash.scm
@@ -0,0 +1,120 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix scripts hash)
+    #:use-module (guix base32)
+    #:use-module (guix ui)
+    #:use-module (guix utils)
+    #:use-module (rnrs io ports)
+    #:use-module (rnrs files)
+    #:use-module (ice-9 match)
+    #:use-module (srfi srfi-1)
+    #:use-module (srfi srfi-26)
+    #:use-module (srfi srfi-37)
+    #:export (guix-hash))
+
+\f
+;;;
+;;; Command-line options.
+;;;
+
+(define %default-options
+  ;; Alist of default option values.
+  `((format . ,bytevector->nix-base32-string)))
+
+(define (show-help)
+  (display (_ "Usage: guix hash [OPTION] FILE
+Return the cryptographic hash of FILE.
+
+Supported formats: 'nix-base32' (default), 'base32', and 'base16'
+('hex' and 'hexadecimal' can be used as well).\n"))
+  (format #t (_ "
+  -f, --format=FMT       write the hash in the given format"))
+  (newline)
+  (display (_ "
+  -h, --help             display this help and exit"))
+  (display (_ "
+  -V, --version          display version information and exit"))
+  (newline)
+  (show-bug-report-information))
+
+(define %options
+  ;; Specification of the command-line options.
+  (list (option '(#\f "format") #t #f
+                (lambda (opt name arg result)
+                  (define fmt-proc
+                    (match arg
+                      ("nix-base32"
+                       bytevector->nix-base32-string)
+                      ("base32"
+                       bytevector->base32-string)
+                      ((or "base16" "hex" "hexadecimal")
+                       bytevector->base16-string)
+                      (x
+                       (leave (_ "unsupported hash format: ~a~%")
+                              arg))))
+
+                  (alist-cons 'format fmt-proc
+                              (alist-delete 'format result))))
+
+        (option '(#\h "help") #f #f
+                (lambda args
+                  (show-help)
+                  (exit 0)))
+        (option '(#\V "version") #f #f
+                (lambda args
+                  (show-version-and-exit "guix hash")))))
+
+
+\f
+;;;
+;;; Entry point.
+;;;
+
+(define (guix-hash . args)
+  (define (parse-options)
+    ;; Return the alist of option values.
+    (args-fold args %options
+               (lambda (opt name arg result)
+                 (leave (_ "unrecognized option: ~a~%")
+                        name))
+               (lambda (arg result)
+                 (alist-cons 'argument arg result))
+               %default-options))
+
+    (let* ((opts (parse-options))
+           (args (filter-map (match-lambda
+                              (('argument . value)
+                               value)
+                              (_ #f))
+                             (reverse opts)))
+           (fmt  (assq-ref opts 'format)))
+
+      (match args
+        ((file)
+         (catch 'system-error
+           (lambda ()
+             (format #t "~a~%"
+                     (call-with-input-file file
+                       (compose fmt sha256 get-bytevector-all))))
+           (lambda args
+             (leave (_ "~a~%")
+                    (strerror (system-error-errno args))))))
+        (_
+         (leave (_ "wrong number of arguments~%"))))))
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 528e7a6..3b01e2a 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,6 +8,7 @@ guix/scripts/build.scm
 guix/scripts/download.scm
 guix/scripts/package.scm
 guix/scripts/gc.scm
+guix/scripts/hash.scm
 guix/scripts/pull.scm
 guix/gnu-maintenance.scm
 guix/ui.scm
-- 
1.7.5.4


[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH] Add 'guix hash'.
  2013-04-21 18:14       ` [PATCH] Add 'guix hash' Nikita Karetnikov
@ 2013-04-21 19:02         ` Ludovic Courtès
  0 siblings, 0 replies; 28+ messages in thread
From: Ludovic Courtès @ 2013-04-21 19:02 UTC (permalink / raw)
  To: Nikita Karetnikov; +Cc: bug-guix

Nikita Karetnikov <nikita@karetnikov.org> skribis:

> OK, can I push this version?

Yep!

Ludo’.

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2013-04-21 19:02 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-01  5:06 [PATCH] Add 'guix hash' Nikita Karetnikov
2013-04-03  8:34 ` Ludovic Courtès
2013-04-05 14:04   ` Nikita Karetnikov
2013-04-05 14:14     ` Nikita Karetnikov
2013-04-05 16:15       ` Ludovic Courtès
2013-04-10 11:48         ` Nikita Karetnikov
2013-04-10 11:54           ` Ludovic Courtès
2013-04-10 12:21             ` Nikita Karetnikov
2013-04-10 17:30               ` Ludovic Courtès
2013-04-05 16:13     ` Ludovic Courtès
2013-04-09 16:28       ` Nikita Karetnikov
2013-04-11 20:35         ` Ludovic Courtès
2013-04-12  5:24           ` master: FAIL: tests/guix-package.sh (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
2013-04-12  6:48             ` master: FAIL: tests/guix-package.sh Nikita Karetnikov
2013-04-12 16:24             ` Ludovic Courtès
2013-04-18  5:01       ` Enhanced 'warning' (was: [PATCH] Add 'guix hash'.) Nikita Karetnikov
2013-04-18  5:06         ` Enhanced 'warning' Nikita Karetnikov
2013-04-18 11:55         ` Ludovic Courtès
2013-04-18 19:27           ` Nikita Karetnikov
2013-04-18 20:59             ` Ludovic Courtès
2013-04-19 20:16               ` [PATCH] ui: Add a 'define-diagnostic' macro. (was: Enhanced 'warning') Nikita Karetnikov
2013-04-20  5:48                 ` [PATCH] ui: Add a 'define-diagnostic' macro Nikita Karetnikov
2013-04-20  9:10                   ` Ludovic Courtès
2013-04-20 17:33                     ` Nikita Karetnikov
2013-04-20 19:55                       ` Ludovic Courtès
2013-04-20  9:09                 ` Ludovic Courtès
2013-04-21 18:14       ` [PATCH] Add 'guix hash' Nikita Karetnikov
2013-04-21 19:02         ` 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).