hackage.scm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  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. ('inputs ('list 'ghc-http))
  190. ('home-page "http://test.org")
  191. ('synopsis (? string?))
  192. ('description (? string?))
  193. ('license 'license:bsd-3)))
  194. (define* (eval-test-with-cabal test-cabal matcher #:key (cabal-environment '()))
  195. (define port (open-input-string test-cabal))
  196. (matcher (hackage->guix-package "foo" #:port port #:cabal-environment cabal-environment)))
  197. (test-assert "hackage->guix-package test 1"
  198. (eval-test-with-cabal test-cabal-1 match-ghc-foo))
  199. (test-assert "hackage->guix-package test 2"
  200. (eval-test-with-cabal test-cabal-2 match-ghc-foo))
  201. (test-assert "hackage->guix-package test 3"
  202. (eval-test-with-cabal test-cabal-3 match-ghc-foo
  203. #:cabal-environment '(("impl" . "ghc-7.8"))))
  204. (test-assert "hackage->guix-package test 4"
  205. (eval-test-with-cabal test-cabal-4 match-ghc-foo
  206. #:cabal-environment '(("impl" . "ghc-7.8"))))
  207. (test-assert "hackage->guix-package test 5"
  208. (eval-test-with-cabal test-cabal-5 match-ghc-foo
  209. #:cabal-environment '(("impl" . "ghc-7.8"))))
  210. (define-package-matcher match-ghc-foo-6
  211. ('package
  212. ('name "ghc-foo")
  213. ('version "1.0.0")
  214. ('source
  215. ('origin
  216. ('method 'url-fetch)
  217. ('uri ('hackage-uri "foo" 'version))
  218. ('sha256
  219. ('base32
  220. (? string? hash)))))
  221. ('build-system 'haskell-build-system)
  222. ('inputs ('list 'ghc-b 'ghc-http))
  223. ('native-inputs ('list 'ghc-haskell-gi))
  224. ('home-page "http://test.org")
  225. ('synopsis (? string?))
  226. ('description (? string?))
  227. ('license 'license:bsd-3)))
  228. (test-assert "hackage->guix-package test 6"
  229. (eval-test-with-cabal test-cabal-6 match-ghc-foo-6))
  230. ;; Check multi-line layouted description.
  231. (define test-cabal-multiline-layout
  232. "name: foo
  233. version: 1.0.0
  234. homepage: http://test.org
  235. synopsis: synopsis
  236. description: first line
  237. second line
  238. license: BSD3
  239. executable cabal
  240. build-depends:
  241. HTTP >= 4000.2.5 && < 4000.3,
  242. mtl >= 2.0 && < 3
  243. ")
  244. (test-assert "hackage->guix-package test multiline desc (layout)"
  245. (eval-test-with-cabal test-cabal-multiline-layout match-ghc-foo))
  246. ;; Check multi-line braced description.
  247. (define test-cabal-multiline-braced
  248. "name: foo
  249. version: 1.0.0
  250. homepage: http://test.org
  251. synopsis: synopsis
  252. description: {
  253. first line
  254. second line
  255. }
  256. license: BSD3
  257. executable cabal
  258. build-depends:
  259. HTTP >= 4000.2.5 && < 4000.3,
  260. mtl >= 2.0 && < 3
  261. ")
  262. (test-assert "hackage->guix-package test multiline desc (braced)"
  263. (eval-test-with-cabal test-cabal-multiline-braced match-ghc-foo))
  264. ;; Check mixed layout. Compare e.g. warp.
  265. (define test-cabal-mixed-layout
  266. "name: foo
  267. version: 1.0.0
  268. homepage: http://test.org
  269. synopsis: synopsis
  270. description: description
  271. license: BSD3
  272. executable cabal
  273. build-depends:
  274. HTTP >= 4000.2.5 && < 4000.3,
  275. mtl >= 2.0 && < 3
  276. ghc-options: -Wall
  277. ")
  278. ;; Fails: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=35743
  279. (test-expect-fail 1)
  280. (test-assert "hackage->guix-package test mixed layout"
  281. (eval-test-with-cabal test-cabal-mixed-layout match-ghc-foo))
  282. ;; Check flag executable. Compare e.g. darcs.
  283. (define test-cabal-flag-executable
  284. "name: foo
  285. version: 1.0.0
  286. homepage: http://test.org
  287. synopsis: synopsis
  288. description: description
  289. license: BSD3
  290. flag executable
  291. description: Build executable
  292. default: True
  293. executable cabal
  294. if !flag(executable)
  295. buildable: False
  296. else
  297. buildable: True
  298. build-depends:
  299. HTTP >= 4000.2.5 && < 4000.3,
  300. mtl >= 2.0 && < 3
  301. ")
  302. (test-assert "hackage->guix-package test flag executable"
  303. (eval-test-with-cabal test-cabal-flag-executable match-ghc-foo))
  304. ;; There is no mandatory space between property name and value.
  305. (define test-cabal-property-no-space
  306. "name:foo
  307. version:1.0.0
  308. homepage:http://test.org
  309. synopsis:synopsis
  310. description:description
  311. license:BSD3
  312. common bench-defaults
  313. ghc-options:-Wall
  314. executable cabal
  315. build-depends:
  316. HTTP >= 4000.2.5 && < 4000.3,
  317. mtl >= 2.0 && < 3
  318. ")
  319. (test-assert "hackage->guix-package test properties without space"
  320. (eval-test-with-cabal test-cabal-property-no-space match-ghc-foo))
  321. ;; There may be no final newline terminating a property.
  322. (define test-cabal-no-final-newline
  323. "name: foo
  324. version: 1.0.0
  325. homepage: http://test.org
  326. synopsis: synopsis
  327. description: description
  328. license: BSD3
  329. executable cabal
  330. build-depends: HTTP >= 4000.2.5 && < 4000.3, mtl >= 2.0 && < 3")
  331. (test-expect-fail 1)
  332. (test-assert "hackage->guix-package test without final newline"
  333. (eval-test-with-cabal test-cabal-no-final-newline match-ghc-foo))
  334. ;; Make sure internal libraries will not be part of the dependencies,
  335. ;; ignore case.
  336. (define test-cabal-internal-library-ignored
  337. "name: foo
  338. version: 1.0.0
  339. homepage: http://test.org
  340. synopsis: synopsis
  341. description: description
  342. license: BSD3
  343. executable cabal
  344. build-depends:
  345. HTTP >= 4000.2.5 && < 4000.3,
  346. internAl
  347. library internaL
  348. build-depends: mtl >= 2.0 && < 3
  349. ")
  350. (test-assert "hackage->guix-package test internal libraries are ignored"
  351. (eval-test-with-cabal test-cabal-internal-library-ignored match-ghc-foo))
  352. ;; Check if-elif-else statements
  353. (define test-cabal-if
  354. "name: foo
  355. version: 1.0.0
  356. homepage: http://test.org
  357. synopsis: synopsis
  358. description: description
  359. license: BSD3
  360. library
  361. if os(first)
  362. Build-depends: ghc-c
  363. ")
  364. (define test-cabal-else
  365. "name: foo
  366. version: 1.0.0
  367. homepage: http://test.org
  368. synopsis: synopsis
  369. description: description
  370. license: BSD3
  371. library
  372. if os(first)
  373. Build-depends: ghc-a
  374. else
  375. Build-depends: ghc-c
  376. ")
  377. (define test-cabal-elif
  378. "name: foo
  379. version: 1.0.0
  380. homepage: http://test.org
  381. synopsis: synopsis
  382. description: description
  383. license: BSD3
  384. library
  385. if os(first)
  386. Build-depends: ghc-a
  387. elif os(second)
  388. Build-depends: ghc-b
  389. elif os(guix)
  390. Build-depends: ghc-c
  391. elif os(third)
  392. Build-depends: ghc-d
  393. else
  394. Build-depends: ghc-e
  395. ")
  396. ;; Try the same with different bracket styles
  397. (define test-cabal-elif-brackets
  398. "name: foo
  399. version: 1.0.0
  400. homepage: http://test.org
  401. synopsis: synopsis
  402. description: description
  403. license: BSD3
  404. library
  405. if os(first) {
  406. Build-depends: ghc-a
  407. }
  408. elif os(second)
  409. Build-depends: ghc-b
  410. elif os(guix) { Build-depends: ghc-c }
  411. elif os(third) {
  412. Build-depends: ghc-d }
  413. elif os(fourth)
  414. {
  415. Build-depends: ghc-d
  416. } else
  417. Build-depends: ghc-e
  418. ")
  419. (define-package-matcher match-ghc-elif
  420. ('package
  421. ('name "ghc-foo")
  422. ('version "1.0.0")
  423. ('source
  424. ('origin
  425. ('method 'url-fetch)
  426. ('uri ('hackage-uri "foo" 'version))
  427. ('sha256
  428. ('base32
  429. (? string? hash)))))
  430. ('build-system 'haskell-build-system)
  431. ('inputs ('list 'ghc-c))
  432. ('home-page "http://test.org")
  433. ('synopsis (? string?))
  434. ('description (? string?))
  435. ('license 'license:bsd-3)))
  436. (test-assert "hackage->guix-package test lonely if statement"
  437. (eval-test-with-cabal test-cabal-else match-ghc-elif
  438. #:cabal-environment '(("os" . "guix"))))
  439. (test-assert "hackage->guix-package test else statement"
  440. (eval-test-with-cabal test-cabal-else match-ghc-elif
  441. #:cabal-environment '(("os" . "guix"))))
  442. (test-assert "hackage->guix-package test elif statement"
  443. (eval-test-with-cabal test-cabal-elif match-ghc-elif
  444. #:cabal-environment '(("os" . "guix"))))
  445. (test-assert "hackage->guix-package test elif statement with brackets"
  446. (eval-test-with-cabal test-cabal-elif-brackets match-ghc-elif
  447. #:cabal-environment '(("os" . "guix"))))
  448. ;; Check Hackage Cabal revisions.
  449. (define test-cabal-revision
  450. "name: foo
  451. version: 1.0.0
  452. x-revision: 2
  453. homepage: http://test.org
  454. synopsis: synopsis
  455. description: description
  456. license: BSD3
  457. executable cabal
  458. build-depends:
  459. HTTP >= 4000.2.5 && < 4000.3,
  460. mtl >= 2.0 && < 3
  461. ")
  462. (define-package-matcher match-ghc-foo-revision
  463. ('package
  464. ('name "ghc-foo")
  465. ('version "1.0.0")
  466. ('source
  467. ('origin
  468. ('method 'url-fetch)
  469. ('uri ('hackage-uri "foo" 'version))
  470. ('sha256
  471. ('base32
  472. (? string? hash)))))
  473. ('build-system 'haskell-build-system)
  474. ('inputs ('list 'ghc-http))
  475. ('arguments
  476. ('quasiquote
  477. ('#:cabal-revision
  478. ("2" "0xxd88fb659f0krljidbvvmkh9ppjnx83j0nqzx8whcg4n5qbyng"))))
  479. ('home-page "http://test.org")
  480. ('synopsis (? string?))
  481. ('description (? string?))
  482. ('license 'license:bsd-3)))
  483. (test-assert "hackage->guix-package test cabal revision"
  484. (eval-test-with-cabal test-cabal-revision match-ghc-foo-revision))
  485. (test-assert "read-cabal test 1"
  486. (match (call-with-input-string test-read-cabal-1 read-cabal)
  487. ((("name" ("test-me"))
  488. ('section 'library #f
  489. (('if ('flag "base4point8")
  490. (("build-depends" ("base >= 4.8 && < 5")))
  491. (('if ('flag "base4")
  492. (("build-depends" ("base >= 4 && < 4.8")))
  493. (('if ('flag "base3")
  494. (("build-depends" ("base >= 3 && < 4")))
  495. (("build-depends" ("base < 3"))))))))
  496. ('if ('or ('flag "base4point8")
  497. ('and ('flag "base4") ('flag "base3")))
  498. (("build-depends" ("random")))
  499. ())
  500. ("build-depends" ("containers"))
  501. ("exposed-modules" ("Test.QuickCheck.Exception")))))
  502. #t)
  503. (x (pk 'fail x #f))))
  504. (test-assert "read-cabal test: if brackets on the same line"
  505. (match (call-with-input-string test-read-cabal-2 read-cabal)
  506. ((("name" ("test-me"))
  507. ('section 'common "defaults"
  508. (('if ('os "foobar")
  509. (("cc-options" ("-DBARBAZ ")))
  510. ()))))
  511. #t)
  512. (x (pk 'fail x #f))))
  513. (test-expect-fail 1)
  514. (test-assert "read-cabal test: property brackets on new line"
  515. (match (call-with-input-string test-read-cabal-brackets-newline read-cabal)
  516. ((("name" ("test-me"))
  517. ('section 'common "defaults"
  518. (("build-depends" ("foobar , barbaz")))))
  519. #t)
  520. (x (pk 'fail x #f))))
  521. (test-assert "read-cabal test: library name"
  522. (match (call-with-input-string test-read-cabal-library-name read-cabal)
  523. ((("name" ("test-me"))
  524. ('section 'library "foobar"
  525. (("build-depends" ("foo, bar"))))
  526. ('section 'library #f
  527. (("build-depends" ("bar, baz")))))
  528. #t)
  529. (x (pk 'fail x #f))))
  530. (define test-cabal-import
  531. "name: foo
  532. version: 1.0.0
  533. homepage: http://test.org
  534. synopsis: synopsis
  535. description: description
  536. license: BSD3
  537. common commons
  538. build-depends:
  539. HTTP >= 4000.2.5 && < 4000.3,
  540. mtl >= 2.0 && < 3
  541. executable cabal
  542. import: commons
  543. ")
  544. (define-package-matcher match-ghc-foo-import
  545. ('package
  546. ('name "ghc-foo")
  547. ('version "1.0.0")
  548. ('source
  549. ('origin
  550. ('method 'url-fetch)
  551. ('uri ('hackage-uri "foo" 'version))
  552. ('sha256
  553. ('base32
  554. (? string? hash)))))
  555. ('build-system 'haskell-build-system)
  556. ('inputs ('list 'ghc-http))
  557. ('home-page "http://test.org")
  558. ('synopsis (? string?))
  559. ('description (? string?))
  560. ('license 'license:bsd-3)))
  561. (test-assert "hackage->guix-package test cabal import"
  562. (eval-test-with-cabal test-cabal-import match-ghc-foo-import))
  563. (test-end "hackage")