copy.scm 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2016, 2017, 2019 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 copy)
  19. #:use-module (guix ui)
  20. #:use-module (guix scripts)
  21. #:use-module (guix ssh)
  22. #:use-module (guix store)
  23. #:use-module ((guix status) #:select (with-status-verbosity))
  24. #:use-module (guix utils)
  25. #:use-module (guix derivations)
  26. #:use-module (guix scripts build)
  27. #:use-module ((guix scripts archive) #:select (options->derivations+files))
  28. #:use-module (srfi srfi-1)
  29. #:use-module (srfi srfi-11)
  30. #:use-module (srfi srfi-37)
  31. #:use-module (ice-9 match)
  32. #:use-module (ice-9 format)
  33. #:export (guix-copy))
  34. ;;;
  35. ;;; Exchanging store items over SSH.
  36. ;;;
  37. (define (ssh-spec->user+host+port spec)
  38. "Parse SPEC, a string like \"user@host:port\" or just \"host\", and return
  39. three values: the user name (or #f), the host name, and the TCP port
  40. number (or #f) corresponding to SPEC."
  41. (define tokens
  42. (char-set #\@ #\:))
  43. (match (string-tokenize spec (char-set-complement tokens))
  44. ((host)
  45. (values #f host #f))
  46. ((left right)
  47. (if (string-index spec #\@)
  48. (values left right #f)
  49. (values #f left (string->number right))))
  50. ((user host port)
  51. (match (string->number port)
  52. ((? integer? port)
  53. (values user host port))
  54. (x
  55. (leave (G_ "~a: invalid TCP port number~%") port))))
  56. (x
  57. (leave (G_ "~a: invalid SSH specification~%") spec))))
  58. (define (send-to-remote-host target opts)
  59. "Send ITEMS to TARGET. ITEMS is a list of store items or package names; for ;
  60. package names, build the underlying packages before sending them."
  61. (with-store local
  62. (set-build-options-from-command-line local opts)
  63. (let-values (((user host port)
  64. (ssh-spec->user+host+port target))
  65. ((drv items)
  66. (options->derivations+files local opts)))
  67. (show-what-to-build local drv
  68. #:use-substitutes? (assoc-ref opts 'substitutes?)
  69. #:dry-run? (assoc-ref opts 'dry-run?))
  70. (and (or (assoc-ref opts 'dry-run?)
  71. (build-derivations local drv))
  72. (let* ((session (open-ssh-session host #:user user
  73. #:port (or port 22)))
  74. (sent (send-files local items
  75. (connect-to-remote-daemon session)
  76. #:recursive? #t)))
  77. (format #t "~{~a~%~}" sent)
  78. sent)))))
  79. (define (retrieve-from-remote-host source opts)
  80. "Retrieve ITEMS from SOURCE."
  81. (with-store local
  82. (let*-values (((user host port)
  83. (ssh-spec->user+host+port source))
  84. ((session)
  85. (open-ssh-session host #:user user #:port (or port 22)))
  86. ((remote)
  87. (connect-to-remote-daemon session)))
  88. (set-build-options-from-command-line local opts)
  89. ;; TODO: Here we could to compute and build the derivations on REMOTE
  90. ;; rather than on LOCAL (one-off offloading) but that is currently too
  91. ;; slow due to the many RPC round trips. So we just assume that REMOTE
  92. ;; contains ITEMS.
  93. (let*-values (((drv items)
  94. (options->derivations+files local opts))
  95. ((retrieved)
  96. (retrieve-files local items remote #:recursive? #t)))
  97. (format #t "~{~a~%~}" retrieved)
  98. retrieved))))
  99. ;;;
  100. ;;; Options.
  101. ;;;
  102. (define (show-help)
  103. (display (G_ "Usage: guix copy [OPTION]... ITEMS...
  104. Copy ITEMS to or from the specified host over SSH.\n"))
  105. (display (G_ "
  106. --to=HOST send ITEMS to HOST"))
  107. (display (G_ "
  108. --from=HOST receive ITEMS from HOST"))
  109. (display (G_ "
  110. -v, --verbosity=LEVEL use the given verbosity LEVEL"))
  111. (newline)
  112. (show-build-options-help)
  113. (newline)
  114. (display (G_ "
  115. -h, --help display this help and exit"))
  116. (display (G_ "
  117. -V, --version display version information and exit"))
  118. (newline)
  119. (show-bug-report-information))
  120. (define %options
  121. ;; Specifications of the command-line options.
  122. (cons* (option '("to") #t #f
  123. (lambda (opt name arg result)
  124. (alist-cons 'destination arg result)))
  125. (option '("from") #t #f
  126. (lambda (opt name arg result)
  127. (alist-cons 'source arg result)))
  128. (option '(#\v "verbosity") #t #f
  129. (lambda (opt name arg result)
  130. (let ((level (string->number* arg)))
  131. (alist-cons 'verbosity level
  132. (alist-delete 'verbosity result)))))
  133. (option '(#\h "help") #f #f
  134. (lambda args
  135. (show-help)
  136. (exit 0)))
  137. (option '(#\V "version") #f #f
  138. (lambda args
  139. (show-version-and-exit "guix copy")))
  140. (option '(#\s "system") #t #f
  141. (lambda (opt name arg result)
  142. (alist-cons 'system arg
  143. (alist-delete 'system result eq?))))
  144. %standard-build-options))
  145. (define %default-options
  146. `((system . ,(%current-system))
  147. (substitutes? . #t)
  148. (offload? . #t)
  149. (graft? . #t)
  150. (print-build-trace? . #t)
  151. (print-extended-build-trace? . #t)
  152. (multiplexed-build-output? . #t)
  153. (debug . 0)
  154. (verbosity . 2)))
  155. ;;;
  156. ;;; Entry point.
  157. ;;;
  158. (define (guix-copy . args)
  159. (with-error-handling
  160. (let* ((opts (parse-command-line args %options (list %default-options)))
  161. (source (assoc-ref opts 'source))
  162. (target (assoc-ref opts 'destination)))
  163. (with-status-verbosity (assoc-ref opts 'verbosity)
  164. (cond (target (send-to-remote-host target opts))
  165. (source (retrieve-from-remote-host source opts))
  166. (else (leave (G_ "use '--to' or '--from'~%"))))))))