download.scm 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2012, 2013, 2015, 2016, 2017, 2020 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (guix scripts download)
  20. #:use-module (guix ui)
  21. #:use-module (guix scripts)
  22. #:use-module (guix store)
  23. #:use-module (gcrypt hash)
  24. #:use-module (guix base16)
  25. #:use-module (guix base32)
  26. #:autoload (guix base64) (base64-encode)
  27. #:use-module ((guix download) #:hide (url-fetch))
  28. #:use-module ((guix build download)
  29. #:select (url-fetch))
  30. #:use-module ((guix progress)
  31. #:select (current-terminal-columns))
  32. #:use-module ((guix build syscalls)
  33. #:select (terminal-columns))
  34. #:use-module (web uri)
  35. #:use-module (ice-9 match)
  36. #:use-module (srfi srfi-1)
  37. #:use-module (srfi srfi-26)
  38. #:use-module (srfi srfi-37)
  39. #:export (guix-download))
  40. ;;;
  41. ;;; Command-line options.
  42. ;;;
  43. (define (download-to-file url file)
  44. "Download the file at URI to FILE. Return FILE."
  45. (let ((uri (string->uri url)))
  46. (match (uri-scheme uri)
  47. ((or 'file #f)
  48. (copy-file (uri-path uri) file))
  49. (_
  50. (url-fetch url file #:mirrors %mirrors)))
  51. file))
  52. (define (ensure-valid-store-file-name name)
  53. "Replace any character not allowed in a stror name by an underscore."
  54. (define valid
  55. ;; according to nix/libstore/store-api.cc
  56. (string->char-set (string-append "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  57. "abcdefghijklmnopqrstuvwxyz"
  58. "0123456789" "+-._?=")))
  59. (string-map (lambda (c)
  60. (if (char-set-contains? valid c) c #\_))
  61. name))
  62. (define* (download-to-store* url #:key (verify-certificate? #t))
  63. (with-store store
  64. (download-to-store store url
  65. (ensure-valid-store-file-name (basename url))
  66. #:verify-certificate? verify-certificate?)))
  67. (define %default-options
  68. ;; Alist of default option values.
  69. `((format . ,bytevector->nix-base32-string)
  70. (hash-algorithm . ,(hash-algorithm sha256))
  71. (verify-certificate? . #t)
  72. (download-proc . ,download-to-store*)))
  73. (define (show-help)
  74. (display (G_ "Usage: guix download [OPTION] URL
  75. Download the file at URL to the store or to the given file, and print its
  76. file name and the hash of its contents.\n"))
  77. (newline)
  78. (display (G_ "\
  79. Supported formats: 'base64', 'nix-base32' (default), 'base32',
  80. and 'base16' ('hex' and 'hexadecimal' can be used as well).\n"))
  81. (format #t (G_ "
  82. -f, --format=FMT write the hash in the given format"))
  83. (format #t (G_ "
  84. -H, --hash=ALGORITHM use the given hash ALGORITHM"))
  85. (format #t (G_ "
  86. --no-check-certificate
  87. do not validate the certificate of HTTPS servers "))
  88. (format #t (G_ "
  89. -o, --output=FILE download to FILE"))
  90. (newline)
  91. (display (G_ "
  92. -h, --help display this help and exit"))
  93. (display (G_ "
  94. -V, --version display version information and exit"))
  95. (newline)
  96. (show-bug-report-information))
  97. (define %options
  98. ;; Specifications of the command-line options.
  99. (list (option '(#\f "format") #t #f
  100. (lambda (opt name arg result)
  101. (define fmt-proc
  102. (match arg
  103. ("base64"
  104. base64-encode)
  105. ("nix-base32"
  106. bytevector->nix-base32-string)
  107. ("base32"
  108. bytevector->base32-string)
  109. ((or "base16" "hex" "hexadecimal")
  110. bytevector->base16-string)
  111. (x
  112. (leave (G_ "unsupported hash format: ~a~%") arg))))
  113. (alist-cons 'format fmt-proc
  114. (alist-delete 'format result))))
  115. (option '(#\H "hash") #t #f
  116. (lambda (opt name arg result)
  117. (match (lookup-hash-algorithm (string->symbol arg))
  118. (#f
  119. (leave (G_ "~a: unknown hash algorithm~%") arg))
  120. (algo
  121. (alist-cons 'hash-algorithm algo result)))))
  122. (option '("no-check-certificate") #f #f
  123. (lambda (opt name arg result)
  124. (alist-cons 'verify-certificate? #f result)))
  125. (option '(#\o "output") #t #f
  126. (lambda (opt name arg result)
  127. (alist-cons 'download-proc
  128. (lambda* (url #:key verify-certificate?)
  129. (download-to-file url arg))
  130. (alist-delete 'download result))))
  131. (option '(#\h "help") #f #f
  132. (lambda args
  133. (show-help)
  134. (exit 0)))
  135. (option '(#\V "version") #f #f
  136. (lambda args
  137. (show-version-and-exit "guix download")))))
  138. ;;;
  139. ;;; Entry point.
  140. ;;;
  141. (define-command (guix-download . args)
  142. (category packaging)
  143. (synopsis "download a file to the store and print its hash")
  144. (define (parse-options)
  145. ;; Return the alist of option values.
  146. (parse-command-line args %options (list %default-options)
  147. #:build-options? #f
  148. #:argument-handler
  149. (lambda (arg result)
  150. (when (assq 'argument result)
  151. (leave (G_ "~A: extraneous argument~%") arg))
  152. (alist-cons 'argument arg result))))
  153. (with-error-handling
  154. (let* ((opts (parse-options))
  155. (arg (or (assq-ref opts 'argument)
  156. (leave (G_ "no download URI was specified~%"))))
  157. (uri (or (string->uri arg)
  158. (false-if-exception
  159. (string->uri
  160. (string-append "file://" (canonicalize-path arg))))
  161. (leave (G_ "~a: failed to parse URI~%")
  162. arg)))
  163. (fetch (assq-ref opts 'download-proc))
  164. (path (parameterize ((current-terminal-columns
  165. (terminal-columns)))
  166. (fetch (uri->string uri)
  167. #:verify-certificate?
  168. (assq-ref opts 'verify-certificate?))))
  169. (hash (call-with-input-file
  170. (or path
  171. (leave (G_ "~a: download failed~%")
  172. arg))
  173. (cute port-hash (assoc-ref opts 'hash-algorithm) <>)))
  174. (fmt (assq-ref opts 'format)))
  175. (format #t "~a~%~a~%" path (fmt hash))
  176. #t)))