hackage.scm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
  3. ;;; Copyright © 2019 Robert Vollmert <rob@vllmrt.net>
  4. ;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
  5. ;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
  6. ;;;
  7. ;;; This file is part of GNU Guix.
  8. ;;;
  9. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  10. ;;; under the terms of the GNU General Public License as published by
  11. ;;; the Free Software Foundation; either version 3 of the License, or (at
  12. ;;; your option) any later version.
  13. ;;;
  14. ;;; GNU Guix is distributed in the hope that it will be useful, but
  15. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;;; GNU General Public License for more details.
  18. ;;;
  19. ;;; You should have received a copy of the GNU General Public License
  20. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  21. (define-module (test-hackage)
  22. #:use-module (guix import cabal)
  23. #:use-module (guix import hackage)
  24. #:use-module (guix tests)
  25. #:use-module (srfi srfi-64)
  26. #:use-module (ice-9 match))
  27. (define test-cabal-1
  28. "name: foo
  29. version: 1.0.0
  30. homepage: http://test.org
  31. synopsis: synopsis
  32. description: description
  33. license: BSD3
  34. executable cabal
  35. build-depends:
  36. HTTP >= 4000.2.5 && < 4000.3,
  37. mtl >= 2.0 && < 3
  38. ")
  39. (define test-cabal-2
  40. "name: foo
  41. version: 1.0.0
  42. homepage: http://test.org
  43. synopsis: synopsis
  44. description: description
  45. license: BSD3
  46. executable cabal {
  47. build-depends:
  48. HTTP >= 4000.2.5 && < 4000.3,
  49. mtl >= 2.0 && < 3
  50. }
  51. ")
  52. ;; Check compiler implementation test with and without spaces.
  53. (define test-cabal-3
  54. "name: foo
  55. version: 1.0.0
  56. homepage: http://test.org
  57. synopsis: synopsis
  58. description: description
  59. license: BSD3
  60. library
  61. if impl(ghc >= 7.2 && < 7.6)
  62. Build-depends: ghc-a
  63. if impl(ghc>=7.2&&<7.6)
  64. Build-depends: ghc-b
  65. if impl(ghc == 7.8)
  66. Build-depends:
  67. HTTP >= 4000.2.5 && < 4000.3,
  68. mtl >= 2.0 && < 3
  69. ")
  70. ;; Check "-any", "-none" when name is different.
  71. (define test-cabal-4
  72. "name: foo
  73. version: 1.0.0
  74. homepage: http://test.org
  75. synopsis: synopsis
  76. description: description
  77. license: BSD3
  78. library
  79. if impl(ghcjs -any)
  80. Build-depends: ghc-a
  81. if impl(ghc>=7.2&&<7.6)
  82. Build-depends: ghc-b
  83. if impl(ghc == 7.8)
  84. Build-depends:
  85. HTTP >= 4000.2.5 && < 4000.3,
  86. mtl >= 2.0 && < 3
  87. ")
  88. ;; Check "-any", "-none".
  89. (define test-cabal-5
  90. "name: foo
  91. version: 1.0.0
  92. homepage: http://test.org
  93. synopsis: synopsis
  94. description: description
  95. license: BSD3
  96. library
  97. if impl(ghc == 7.8)
  98. Build-depends:
  99. HTTP >= 4000.2.5 && < 4000.3,
  100. if impl(ghc -any)
  101. Build-depends: mtl >= 2.0 && < 3
  102. if impl(ghc>=7.2&&<7.6)
  103. Build-depends: ghc-b
  104. ")
  105. ;; Check "custom-setup".
  106. (define test-cabal-6
  107. "name: foo
  108. build-type: Custom
  109. version: 1.0.0
  110. homepage: http://test.org
  111. synopsis: synopsis
  112. description: description
  113. license: BSD3
  114. custom-setup
  115. setup-depends: base >= 4.7 && < 5,
  116. Cabal >= 1.24,
  117. haskell-gi == 0.21.*
  118. library
  119. if impl(ghc>=7.2&&<7.6)
  120. Build-depends: ghc-b
  121. if impl(ghc == 7.8)
  122. Build-depends:
  123. HTTP >= 4000.2.5 && < 4000.3,
  124. mtl >= 2.0 && < 3
  125. ")
  126. ;; A fragment of a real Cabal file with minor modification to check precedence
  127. ;; of 'and' over 'or', missing final newline, spaces between keywords and
  128. ;; parentheses and between key and column.
  129. (define test-read-cabal-1
  130. "name: test-me
  131. library
  132. -- Choose which library versions to use.
  133. if flag(base4point8)
  134. Build-depends: base >= 4.8 && < 5
  135. else
  136. if flag(base4)
  137. Build-depends: base >= 4 && < 4.8
  138. else
  139. if flag(base3)
  140. Build-depends: base >= 3 && < 4
  141. else
  142. Build-depends: base < 3
  143. if flag(base4point8) || flag (base4) && flag(base3)
  144. Build-depends: random
  145. Build-depends : containers
  146. -- Modules that are always built.
  147. Exposed-Modules:
  148. Test.QuickCheck.Exception")
  149. (define test-read-cabal-2
  150. "name: test-me
  151. common defaults
  152. if os(foobar) { cc-options: -DBARBAZ }
  153. ") ; Intentional newline.
  154. ;; Test opening bracket on new line.
  155. (define test-read-cabal-brackets-newline
  156. "name: test-me
  157. common defaults
  158. build-depends:
  159. { foobar
  160. , barbaz
  161. }
  162. ")
  163. ;; Test library with (since Cabal 2.0) and without names.
  164. (define test-read-cabal-library-name
  165. "name: test-me
  166. library foobar
  167. build-depends: foo, bar
  168. library
  169. build-depends: bar, baz
  170. ")
  171. (test-begin "hackage")
  172. (define-syntax-rule (define-package-matcher name pattern)
  173. (define* (name obj)
  174. (match obj
  175. (pattern #t)
  176. (x (pk 'fail x #f)))))
  177. (define-package-matcher match-ghc-foo
  178. ('package
  179. ('name "ghc-foo")
  180. ('version "1.0.0")
  181. ('source
  182. ('origin
  183. ('method 'url-fetch)
  184. ('uri ('hackage-uri "foo" 'version))
  185. ('sha256
  186. ('base32
  187. (? string? hash)))))
  188. ('build-system 'haskell-build-system)
  189. ('properties '(quote ((upstream-name . "foo"))))
  190. ('inputs ('list 'ghc-http))
  191. ('home-page "http://test.org")
  192. ('synopsis (? string?))
  193. ('description (? string?))
  194. ('license 'license:bsd-3)))
  195. (define* (eval-test-with-cabal test-cabal matcher #:key (cabal-environment '()))
  196. (define port (open-input-string test-cabal))
  197. (matcher (hackage->guix-package "foo" #:port port #:cabal-environment cabal-environment)))
  198. (test-assert "hackage->guix-package test 1"
  199. (eval-test-with-cabal test-cabal-1 match-ghc-foo))
  200. (test-assert "hackage->guix-package test 2"
  201. (eval-test-with-cabal test-cabal-2 match-ghc-foo))
  202. (test-assert "hackage->guix-package test 3"
  203. (eval-test-with-cabal test-cabal-3 match-ghc-foo
  204. #:cabal-environment '(("impl" . "ghc-7.8"))))
  205. (test-assert "hackage->guix-package test 4"
  206. (eval-test-with-cabal test-cabal-4 match-ghc-foo
  207. #:cabal-environment '(("impl" . "ghc-7.8"))))
  208. (test-assert "hackage->guix-package test 5"
  209. (eval-test-with-cabal test-cabal-5 match-ghc-foo
  210. #:cabal-environment '(("impl" . "ghc-7.8"))))
  211. (define-package-matcher match-ghc-foo-6
  212. ('package
  213. ('name "ghc-foo")
  214. ('version "1.0.0")
  215. ('source
  216. ('origin
  217. ('method 'url-fetch)
  218. ('uri ('hackage-uri "foo" 'version))
  219. ('sha256
  220. ('base32
  221. (? string? hash)))))
  222. ('build-system 'haskell-build-system)
  223. ('properties '(quote ((upstream-name . "foo"))))
  224. ('inputs ('list 'ghc-b 'ghc-http))
  225. ('native-inputs ('list 'ghc-haskell-gi))
  226. ('home-page "http://test.org")
  227. ('synopsis (? string?))
  228. ('description (? string?))
  229. ('license 'license:bsd-3)))
  230. (test-assert "hackage->guix-package test 6"
  231. (eval-test-with-cabal test-cabal-6 match-ghc-foo-6))
  232. ;; Check multi-line layouted description.
  233. (define test-cabal-multiline-layout
  234. "name: foo
  235. version: 1.0.0
  236. homepage: http://test.org
  237. synopsis: synopsis
  238. description: first line
  239. second line
  240. license: BSD3
  241. executable cabal
  242. build-depends:
  243. HTTP >= 4000.2.5 && < 4000.3,
  244. mtl >= 2.0 && < 3
  245. ")
  246. (test-assert "hackage->guix-package test multiline desc (layout)"
  247. (eval-test-with-cabal test-cabal-multiline-layout match-ghc-foo))
  248. ;; Check multi-line braced description.
  249. (define test-cabal-multiline-braced
  250. "name: foo
  251. version: 1.0.0
  252. homepage: http://test.org
  253. synopsis: synopsis
  254. description: {
  255. first line
  256. second line
  257. }
  258. license: BSD3
  259. executable cabal
  260. build-depends:
  261. HTTP >= 4000.2.5 && < 4000.3,
  262. mtl >= 2.0 && < 3
  263. ")
  264. (test-assert "hackage->guix-package test multiline desc (braced)"
  265. (eval-test-with-cabal test-cabal-multiline-braced match-ghc-foo))
  266. ;; Check mixed layout. Compare e.g. warp.
  267. (define test-cabal-mixed-layout
  268. "name: foo
  269. version: 1.0.0
  270. homepage: http://test.org
  271. synopsis: synopsis
  272. description: description
  273. license: BSD3
  274. executable cabal
  275. build-depends:
  276. HTTP >= 4000.2.5 && < 4000.3,
  277. mtl >= 2.0 && < 3
  278. ghc-options: -Wall
  279. ")
  280. ;; Fails: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=35743
  281. (test-expect-fail 1)
  282. (test-assert "hackage->guix-package test mixed layout"
  283. (eval-test-with-cabal test-cabal-mixed-layout match-ghc-foo))
  284. ;; Check flag executable. Compare e.g. darcs.
  285. (define test-cabal-flag-executable
  286. "name: foo
  287. version: 1.0.0
  288. homepage: http://test.org
  289. synopsis: synopsis
  290. description: description
  291. license: BSD3
  292. flag executable
  293. description: Build executable
  294. default: True
  295. executable cabal
  296. if !flag(executable)
  297. buildable: False
  298. else
  299. buildable: True
  300. build-depends:
  301. HTTP >= 4000.2.5 && < 4000.3,
  302. mtl >= 2.0 && < 3
  303. ")
  304. (test-assert "hackage->guix-package test flag executable"
  305. (eval-test-with-cabal test-cabal-flag-executable match-ghc-foo))
  306. ;; There is no mandatory space between property name and value.
  307. (define test-cabal-property-no-space
  308. "name:foo
  309. version:1.0.0
  310. homepage:http://test.org
  311. synopsis:synopsis
  312. description:description
  313. license:BSD3
  314. common bench-defaults
  315. ghc-options:-Wall
  316. executable cabal
  317. build-depends:
  318. HTTP >= 4000.2.5 && < 4000.3,
  319. mtl >= 2.0 && < 3
  320. ")
  321. (test-assert "hackage->guix-package test properties without space"
  322. (eval-test-with-cabal test-cabal-property-no-space match-ghc-foo))
  323. ;; There may be no final newline terminating a property.
  324. (define test-cabal-no-final-newline
  325. "name: foo
  326. version: 1.0.0
  327. homepage: http://test.org
  328. synopsis: synopsis
  329. description: description
  330. license: BSD3
  331. executable cabal
  332. build-depends: HTTP >= 4000.2.5 && < 4000.3, mtl >= 2.0 && < 3")
  333. (test-expect-fail 1)
  334. (test-assert "hackage->guix-package test without final newline"
  335. (eval-test-with-cabal test-cabal-no-final-newline match-ghc-foo))
  336. ;; Make sure internal libraries will not be part of the dependencies,
  337. ;; ignore case.
  338. (define test-cabal-internal-library-ignored
  339. "name: foo
  340. version: 1.0.0
  341. homepage: http://test.org
  342. synopsis: synopsis
  343. description: description
  344. license: BSD3
  345. executable cabal
  346. build-depends:
  347. HTTP >= 4000.2.5 && < 4000.3,
  348. internAl
  349. library internaL
  350. build-depends: mtl >= 2.0 && < 3
  351. ")
  352. (test-assert "hackage->guix-package test internal libraries are ignored"
  353. (eval-test-with-cabal test-cabal-internal-library-ignored match-ghc-foo))
  354. ;; Check if-elif-else statements
  355. (define test-cabal-if
  356. "name: foo
  357. version: 1.0.0
  358. homepage: http://test.org
  359. synopsis: synopsis
  360. description: description
  361. license: BSD3
  362. library
  363. if os(first)
  364. Build-depends: ghc-c
  365. ")
  366. (define test-cabal-else
  367. "name: foo
  368. version: 1.0.0
  369. homepage: http://test.org
  370. synopsis: synopsis
  371. description: description
  372. license: BSD3
  373. library
  374. if os(first)
  375. Build-depends: ghc-a
  376. else
  377. Build-depends: ghc-c
  378. ")
  379. (define test-cabal-elif
  380. "name: foo
  381. version: 1.0.0
  382. homepage: http://test.org
  383. synopsis: synopsis
  384. description: description
  385. license: BSD3
  386. library
  387. if os(first)
  388. Build-depends: ghc-a
  389. elif os(second)
  390. Build-depends: ghc-b
  391. elif os(guix)
  392. Build-depends: ghc-c
  393. elif os(third)
  394. Build-depends: ghc-d
  395. else
  396. Build-depends: ghc-e
  397. ")
  398. ;; Try the same with different bracket styles
  399. (define test-cabal-elif-brackets
  400. "name: foo
  401. version: 1.0.0
  402. homepage: http://test.org
  403. synopsis: synopsis
  404. description: description
  405. license: BSD3
  406. library
  407. if os(first) {
  408. Build-depends: ghc-a
  409. }
  410. elif os(second)
  411. Build-depends: ghc-b
  412. elif os(guix) { Build-depends: ghc-c }
  413. elif os(third) {
  414. Build-depends: ghc-d }
  415. elif os(fourth)
  416. {
  417. Build-depends: ghc-d
  418. } else
  419. Build-depends: ghc-e
  420. ")
  421. (define-package-matcher match-ghc-elif
  422. ('package
  423. ('name "ghc-foo")
  424. ('version "1.0.0")
  425. ('source
  426. ('origin
  427. ('method 'url-fetch)
  428. ('uri ('hackage-uri "foo" 'version))
  429. ('sha256
  430. ('base32
  431. (? string? hash)))))
  432. ('build-system 'haskell-build-system)
  433. ('properties '(quote ((upstream-name . "foo"))))
  434. ('inputs ('list 'ghc-c))
  435. ('home-page "http://test.org")
  436. ('synopsis (? string?))
  437. ('description (? string?))
  438. ('license 'license:bsd-3)))
  439. (test-assert "hackage->guix-package test lonely if statement"
  440. (eval-test-with-cabal test-cabal-else match-ghc-elif
  441. #:cabal-environment '(("os" . "guix"))))
  442. (test-assert "hackage->guix-package test else statement"
  443. (eval-test-with-cabal test-cabal-else match-ghc-elif
  444. #:cabal-environment '(("os" . "guix"))))
  445. (test-assert "hackage->guix-package test elif statement"
  446. (eval-test-with-cabal test-cabal-elif match-ghc-elif
  447. #:cabal-environment '(("os" . "guix"))))
  448. (test-assert "hackage->guix-package test elif statement with brackets"
  449. (eval-test-with-cabal test-cabal-elif-brackets match-ghc-elif
  450. #:cabal-environment '(("os" . "guix"))))
  451. ;; Check Hackage Cabal revisions.
  452. (define test-cabal-revision
  453. "name: foo
  454. version: 1.0.0
  455. x-revision: 2
  456. homepage: http://test.org
  457. synopsis: synopsis
  458. description: description
  459. license: BSD3
  460. executable cabal
  461. build-depends:
  462. HTTP >= 4000.2.5 && < 4000.3,
  463. mtl >= 2.0 && < 3
  464. ")
  465. (define-package-matcher match-ghc-foo-revision
  466. ('package
  467. ('name "ghc-foo")
  468. ('version "1.0.0")
  469. ('source
  470. ('origin
  471. ('method 'url-fetch)
  472. ('uri ('hackage-uri "foo" 'version))
  473. ('sha256
  474. ('base32
  475. (? string? hash)))))
  476. ('build-system 'haskell-build-system)
  477. ('properties '(quote ((upstream-name . "foo"))))
  478. ('inputs ('list 'ghc-http))
  479. ('arguments
  480. ('quasiquote
  481. ('#:cabal-revision
  482. ("2" "0xxd88fb659f0krljidbvvmkh9ppjnx83j0nqzx8whcg4n5qbyng"))))
  483. ('home-page "http://test.org")
  484. ('synopsis (? string?))
  485. ('description (? string?))
  486. ('license 'license:bsd-3)))
  487. (test-assert "hackage->guix-package test cabal revision"
  488. (eval-test-with-cabal test-cabal-revision match-ghc-foo-revision))
  489. (test-assert "read-cabal test 1"
  490. (match (call-with-input-string test-read-cabal-1 read-cabal)
  491. ((("name" ("test-me"))
  492. ('section 'library #f
  493. (('if ('flag "base4point8")
  494. (("build-depends" ("base >= 4.8 && < 5")))
  495. (('if ('flag "base4")
  496. (("build-depends" ("base >= 4 && < 4.8")))
  497. (('if ('flag "base3")
  498. (("build-depends" ("base >= 3 && < 4")))
  499. (("build-depends" ("base < 3"))))))))
  500. ('if ('or ('flag "base4point8")
  501. ('and ('flag "base4") ('flag "base3")))
  502. (("build-depends" ("random")))
  503. ())
  504. ("build-depends" ("containers"))
  505. ("exposed-modules" ("Test.QuickCheck.Exception")))))
  506. #t)
  507. (x (pk 'fail x #f))))
  508. (test-assert "read-cabal test: if brackets on the same line"
  509. (match (call-with-input-string test-read-cabal-2 read-cabal)
  510. ((("name" ("test-me"))
  511. ('section 'common "defaults"
  512. (('if ('os "foobar")
  513. (("cc-options" ("-DBARBAZ ")))
  514. ()))))
  515. #t)
  516. (x (pk 'fail x #f))))
  517. (test-expect-fail 1)
  518. (test-assert "read-cabal test: property brackets on new line"
  519. (match (call-with-input-string test-read-cabal-brackets-newline read-cabal)
  520. ((("name" ("test-me"))
  521. ('section 'common "defaults"
  522. (("build-depends" ("foobar , barbaz")))))
  523. #t)
  524. (x (pk 'fail x #f))))
  525. (test-assert "read-cabal test: library name"
  526. (match (call-with-input-string test-read-cabal-library-name read-cabal)
  527. ((("name" ("test-me"))
  528. ('section 'library "foobar"
  529. (("build-depends" ("foo, bar"))))
  530. ('section 'library #f
  531. (("build-depends" ("bar, baz")))))
  532. #t)
  533. (x (pk 'fail x #f))))
  534. (define test-cabal-import
  535. "name: foo
  536. version: 1.0.0
  537. homepage: http://test.org
  538. synopsis: synopsis
  539. description: description
  540. license: BSD3
  541. common commons
  542. build-depends:
  543. HTTP >= 4000.2.5 && < 4000.3,
  544. mtl >= 2.0 && < 3
  545. executable cabal
  546. import: commons
  547. ")
  548. (define-package-matcher match-ghc-foo-import
  549. ('package
  550. ('name "ghc-foo")
  551. ('version "1.0.0")
  552. ('source
  553. ('origin
  554. ('method 'url-fetch)
  555. ('uri ('hackage-uri "foo" 'version))
  556. ('sha256
  557. ('base32
  558. (? string? hash)))))
  559. ('build-system 'haskell-build-system)
  560. ('properties '(quote ((upstream-name . "foo"))))
  561. ('inputs ('list 'ghc-http))
  562. ('home-page "http://test.org")
  563. ('synopsis (? string?))
  564. ('description (? string?))
  565. ('license 'license:bsd-3)))
  566. (test-assert "hackage->guix-package test cabal import"
  567. (eval-test-with-cabal test-cabal-import match-ghc-foo-import))
  568. (test-end "hackage")