download.scm 6.5 KB

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