union.scm 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2012, 2013, 2014, 2015, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  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 (test-union)
  20. #:use-module (guix tests)
  21. #:use-module (guix store)
  22. #:use-module (guix utils)
  23. #:use-module (guix derivations)
  24. #:use-module (guix packages)
  25. #:use-module (guix build union)
  26. #:use-module ((guix build utils)
  27. #:select (with-directory-excursion directory-exists?))
  28. #:use-module (gnu packages bootstrap)
  29. #:use-module (srfi srfi-1)
  30. #:use-module (srfi srfi-64)
  31. #:use-module (rnrs io ports)
  32. #:use-module (ice-9 match))
  33. ;; Exercise the (guix build union) module.
  34. (define %store
  35. (open-connection-for-tests))
  36. (test-begin "union")
  37. (test-assert "union-build with symlink to directory"
  38. ;; http://bugs.gnu.org/17083
  39. ;; Here both ONE and TWO provide an element called 'foo', but in ONE it's a
  40. ;; directory whereas in TWO it's a symlink to a directory.
  41. (let* ((one (build-expression->derivation
  42. %store "one"
  43. '(begin
  44. (use-modules (guix build utils) (srfi srfi-26))
  45. (let ((foo (string-append %output "/foo")))
  46. (mkdir-p foo)
  47. (call-with-output-file (string-append foo "/one")
  48. (cut display "one" <>))))
  49. #:modules '((guix build utils))))
  50. (two (build-expression->derivation
  51. %store "two"
  52. '(begin
  53. (use-modules (guix build utils) (srfi srfi-26))
  54. (let ((foo (string-append %output "/foo"))
  55. (bar (string-append %output "/bar")))
  56. (mkdir-p bar)
  57. (call-with-output-file (string-append bar "/two")
  58. (cut display "two" <>))
  59. (symlink "bar" foo)))
  60. #:modules '((guix build utils))))
  61. (builder '(begin
  62. (use-modules (guix build union))
  63. (union-build (assoc-ref %outputs "out")
  64. (list (assoc-ref %build-inputs "one")
  65. (assoc-ref %build-inputs "two")))))
  66. (drv
  67. (build-expression->derivation %store "union-collision-symlink"
  68. builder
  69. #:inputs `(("one" ,one) ("two" ,two))
  70. #:modules '((guix build union)))))
  71. (and (build-derivations %store (list drv))
  72. (with-directory-excursion (pk (derivation->output-path drv))
  73. (and (string=? "one"
  74. (call-with-input-file "foo/one" get-string-all))
  75. (string=? "two"
  76. (call-with-input-file "foo/two" get-string-all))
  77. (string=? "two"
  78. (call-with-input-file "bar/two" get-string-all))
  79. (not (file-exists? "bar/one")))))))
  80. (test-skip (if (and %store (network-reachable?))
  81. 0
  82. 1))
  83. (test-assert "union-build"
  84. (let* ((inputs (map (match-lambda
  85. ((name package)
  86. `(,name ,(package-derivation %store package))))
  87. ;; Purposefully leave duplicate entries.
  88. (filter (compose package? cadr)
  89. (append %bootstrap-inputs-for-tests
  90. (take %bootstrap-inputs-for-tests 3)))))
  91. (builder `(begin
  92. (use-modules (guix build union))
  93. (union-build (assoc-ref %outputs "out")
  94. (map cdr %build-inputs))))
  95. (drv
  96. (build-expression->derivation %store "union-test"
  97. builder
  98. #:inputs inputs
  99. #:modules '((guix build union)))))
  100. (and (build-derivations %store (list (pk 'drv drv)))
  101. (with-directory-excursion (derivation->output-path drv)
  102. (and (file-exists? "bin/touch")
  103. (file-exists? "bin/gcc")
  104. (file-exists? "bin/ld")
  105. (file-exists? "lib/libc.so")
  106. (directory-exists? "lib/gcc")
  107. (file-exists? "include/unistd.h")
  108. ;; The 'include/c++' sub-directory is only found in
  109. ;; gcc-bootstrap, so it should be unified in a
  110. ;; straightforward way, without traversing it.
  111. (eq? 'symlink (stat:type (lstat "include/c++")))
  112. ;; Conversely, several inputs have a 'bin' sub-directory, so
  113. ;; unifying it requires traversing them all, and creating a
  114. ;; new 'bin' sub-directory in the profile.
  115. (eq? 'directory (stat:type (lstat "bin"))))))))
  116. (test-assert "union-build collision first & last"
  117. (let* ((guile (package-derivation %store %bootstrap-guile))
  118. (fake (build-expression->derivation
  119. %store "fake-guile"
  120. '(begin
  121. (use-modules (guix build utils))
  122. (let ((out (assoc-ref %outputs "out")))
  123. (mkdir-p (string-append out "/bin"))
  124. (call-with-output-file (string-append out "/bin/guile")
  125. (const #t))))
  126. #:modules '((guix build utils))))
  127. (builder (lambda (policy)
  128. `(begin
  129. (use-modules (guix build union)
  130. (srfi srfi-1))
  131. (union-build (assoc-ref %outputs "out")
  132. (map cdr %build-inputs)
  133. #:resolve-collision ,policy))))
  134. (drv1
  135. (build-expression->derivation %store "union-first"
  136. (builder 'first)
  137. #:inputs `(("guile" ,guile)
  138. ("fake" ,fake))
  139. #:modules '((guix build union))))
  140. (drv2
  141. (build-expression->derivation %store "union-last"
  142. (builder 'last)
  143. #:inputs `(("guile" ,guile)
  144. ("fake" ,fake))
  145. #:modules '((guix build union)))))
  146. (and (build-derivations %store (list drv1 drv2))
  147. (with-directory-excursion (derivation->output-path drv1)
  148. (string=? (readlink "bin/guile")
  149. (string-append (derivation->output-path guile)
  150. "/bin/guile")))
  151. (with-directory-excursion (derivation->output-path drv2)
  152. (string=? (readlink "bin/guile")
  153. (string-append (derivation->output-path fake)
  154. "/bin/guile"))))))
  155. (test-assert "union-build #:create-all-directories? #t"
  156. (let* ((build `(begin
  157. (use-modules (guix build union))
  158. (union-build (assoc-ref %outputs "out")
  159. (map cdr %build-inputs)
  160. #:create-all-directories? #t)))
  161. (input (package-derivation %store %bootstrap-guile))
  162. (drv (build-expression->derivation %store "union-test-all-dirs"
  163. build
  164. #:modules '((guix build union))
  165. #:inputs `(("g" ,input)))))
  166. (and (build-derivations %store (list drv))
  167. (with-directory-excursion (derivation->output-path drv)
  168. ;; Even though there's only one input to the union,
  169. ;; #:create-all-directories? #t must have created bin/ rather than
  170. ;; making it a symlink to Guile's bin/.
  171. (and (file-exists? "bin/guile")
  172. (file-is-directory? "bin")
  173. (eq? 'symlink (stat:type (lstat "bin/guile"))))))))
  174. (letrec-syntax ((test-relative-file-name
  175. (syntax-rules (=>)
  176. ((_ (reference file => expected) rest ...)
  177. (begin
  178. (test-equal (string-append "relative-file-name "
  179. reference " " file)
  180. expected
  181. (relative-file-name reference file))
  182. (test-relative-file-name rest ...)))
  183. ((_)
  184. #t))))
  185. (test-relative-file-name
  186. ("/a/b" "/a/c/d" => "../c/d")
  187. ("/a/b" "/a/b" => "")
  188. ("/a/b" "/a" => "..")
  189. ("/a/b" "/a/b/c/d" => "c/d")
  190. ("/a/b/c" "/a/d/e/f" => "../../d/e/f")))
  191. (test-end)