crate.scm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2014 David Thompson <davet@gnu.org>
  3. ;;; Copyright © 2016 David Craven <david@craven.ch>
  4. ;;; Copyright © 2019, 2020 Ludovic Courtès <ludo@gnu.org>
  5. ;;;
  6. ;;; This file is part of GNU Guix.
  7. ;;;
  8. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  9. ;;; under the terms of the GNU General Public License as published by
  10. ;;; the Free Software Foundation; either version 3 of the License, or (at
  11. ;;; your option) any later version.
  12. ;;;
  13. ;;; GNU Guix is distributed in the hope that it will be useful, but
  14. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;;; GNU General Public License for more details.
  17. ;;;
  18. ;;; You should have received a copy of the GNU General Public License
  19. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  20. (define-module (test-crate)
  21. #:use-module (guix import crate)
  22. #:use-module (guix base32)
  23. #:use-module (guix build-system cargo)
  24. #:use-module (gcrypt hash)
  25. #:use-module (guix tests)
  26. #:use-module (ice-9 iconv)
  27. #:use-module (ice-9 match)
  28. #:use-module (srfi srfi-64))
  29. (define test-foo-crate
  30. "{
  31. \"crate\": {
  32. \"max_version\": \"1.0.0\",
  33. \"name\": \"foo\",
  34. \"description\": \"summary\",
  35. \"homepage\": \"http://example.com\",
  36. \"repository\": \"http://example.com\",
  37. \"keywords\": [\"dummy\" \"test\"],
  38. \"categories\": [\"test\"]
  39. \"actual_versions\": [
  40. { \"id\": \"foo\",
  41. \"num\": \"1.0.0\",
  42. \"license\": \"MIT OR Apache-2.0\",
  43. \"links\": {
  44. \"dependencies\": \"/api/v1/crates/foo/1.0.0/dependencies\"
  45. }
  46. }
  47. ]
  48. }
  49. }")
  50. (define test-foo-dependencies
  51. "{
  52. \"dependencies\": [
  53. {
  54. \"crate_id\": \"bar\",
  55. \"kind\": \"normal\"
  56. }
  57. ]
  58. }")
  59. (define test-root-crate
  60. "{
  61. \"crate\": {
  62. \"max_version\": \"1.0.0\",
  63. \"name\": \"root\",
  64. \"description\": \"summary\",
  65. \"homepage\": \"http://example.com\",
  66. \"repository\": \"http://example.com\",
  67. \"keywords\": [\"dummy\" \"test\"],
  68. \"categories\": [\"test\"]
  69. \"actual_versions\": [
  70. { \"id\": \"foo\",
  71. \"num\": \"1.0.0\",
  72. \"license\": \"MIT OR Apache-2.0\",
  73. \"links\": {
  74. \"dependencies\": \"/api/v1/crates/root/1.0.0/dependencies\"
  75. }
  76. }
  77. ]
  78. }
  79. }")
  80. (define test-root-dependencies
  81. "{
  82. \"dependencies\": [
  83. {
  84. \"crate_id\": \"intermediate-1\",
  85. \"kind\": \"normal\"
  86. },
  87. {
  88. \"crate_id\": \"intermediate-2\",
  89. \"kind\": \"normal\"
  90. }
  91. {
  92. \"crate_id\": \"leaf-alice\",
  93. \"kind\": \"normal\"
  94. },
  95. {
  96. \"crate_id\": \"leaf-bob\",
  97. \"kind\": \"normal\"
  98. }
  99. ]
  100. }")
  101. (define test-intermediate-1-crate
  102. "{
  103. \"crate\": {
  104. \"max_version\": \"1.0.0\",
  105. \"name\": \"intermediate-1\",
  106. \"description\": \"summary\",
  107. \"homepage\": \"http://example.com\",
  108. \"repository\": \"http://example.com\",
  109. \"keywords\": [\"dummy\" \"test\"],
  110. \"categories\": [\"test\"]
  111. \"actual_versions\": [
  112. { \"id\": \"intermediate-1\",
  113. \"num\": \"1.0.0\",
  114. \"license\": \"MIT OR Apache-2.0\",
  115. \"links\": {
  116. \"dependencies\": \"/api/v1/crates/intermediate-1/1.0.0/dependencies\"
  117. }
  118. }
  119. ]
  120. }
  121. }")
  122. (define test-intermediate-1-dependencies
  123. "{
  124. \"dependencies\": [
  125. {
  126. \"crate_id\": \"intermediate-2\",
  127. \"kind\": \"normal\"
  128. },
  129. {
  130. \"crate_id\": \"leaf-alice\",
  131. \"kind\": \"normal\"
  132. },
  133. {
  134. \"crate_id\": \"leaf-bob\",
  135. \"kind\": \"normal\"
  136. }
  137. ]
  138. }")
  139. (define test-intermediate-2-crate
  140. "{
  141. \"crate\": {
  142. \"max_version\": \"1.0.0\",
  143. \"name\": \"intermediate-2\",
  144. \"description\": \"summary\",
  145. \"homepage\": \"http://example.com\",
  146. \"repository\": \"http://example.com\",
  147. \"keywords\": [\"dummy\" \"test\"],
  148. \"categories\": [\"test\"]
  149. \"actual_versions\": [
  150. { \"id\": \"intermediate-2\",
  151. \"num\": \"1.0.0\",
  152. \"license\": \"MIT OR Apache-2.0\",
  153. \"links\": {
  154. \"dependencies\": \"/api/v1/crates/intermediate-2/1.0.0/dependencies\"
  155. }
  156. }
  157. ]
  158. }
  159. }")
  160. (define test-intermediate-2-dependencies
  161. "{
  162. \"dependencies\": [
  163. {
  164. \"crate_id\": \"leaf-bob\",
  165. \"kind\": \"normal\"
  166. }
  167. ]
  168. }")
  169. (define test-leaf-alice-crate
  170. "{
  171. \"crate\": {
  172. \"max_version\": \"1.0.0\",
  173. \"name\": \"leaf-alice\",
  174. \"description\": \"summary\",
  175. \"homepage\": \"http://example.com\",
  176. \"repository\": \"http://example.com\",
  177. \"keywords\": [\"dummy\" \"test\"],
  178. \"categories\": [\"test\"]
  179. \"actual_versions\": [
  180. { \"id\": \"leaf-alice\",
  181. \"num\": \"1.0.0\",
  182. \"license\": \"MIT OR Apache-2.0\",
  183. \"links\": {
  184. \"dependencies\": \"/api/v1/crates/leaf-alice/1.0.0/dependencies\"
  185. }
  186. }
  187. ]
  188. }
  189. }")
  190. (define test-leaf-alice-dependencies
  191. "{
  192. \"dependencies\": []
  193. }")
  194. (define test-leaf-bob-crate
  195. "{
  196. \"crate\": {
  197. \"max_version\": \"1.0.0\",
  198. \"name\": \"leaf-bob\",
  199. \"description\": \"summary\",
  200. \"homepage\": \"http://example.com\",
  201. \"repository\": \"http://example.com\",
  202. \"keywords\": [\"dummy\" \"test\"],
  203. \"categories\": [\"test\"]
  204. \"actual_versions\": [
  205. { \"id\": \"leaf-bob\",
  206. \"num\": \"1.0.0\",
  207. \"license\": \"MIT OR Apache-2.0\",
  208. \"links\": {
  209. \"dependencies\": \"/api/v1/crates/leaf-bob/1.0.0/dependencies\"
  210. }
  211. }
  212. ]
  213. }
  214. }")
  215. (define test-leaf-bob-dependencies
  216. "{
  217. \"dependencies\": []
  218. }")
  219. (define test-source-hash
  220. "")
  221. (test-begin "crate")
  222. (test-equal "guix-package->crate-name"
  223. "rustc-serialize"
  224. (guix-package->crate-name
  225. (dummy-package
  226. "rust-rustc-serialize"
  227. (source (dummy-origin
  228. (uri (crate-uri "rustc-serialize" "1.0")))))))
  229. (test-assert "crate->guix-package"
  230. ;; Replace network resources with sample data.
  231. (mock ((guix http-client) http-fetch
  232. (lambda (url . rest)
  233. (match url
  234. ("https://crates.io/api/v1/crates/foo"
  235. (open-input-string test-foo-crate))
  236. ("https://crates.io/api/v1/crates/foo/1.0.0/download"
  237. (set! test-source-hash
  238. (bytevector->nix-base32-string
  239. (sha256 (string->bytevector "empty file\n" "utf-8"))))
  240. (open-input-string "empty file\n"))
  241. ("https://crates.io/api/v1/crates/foo/1.0.0/dependencies"
  242. (open-input-string test-foo-dependencies))
  243. (_ (error "Unexpected URL: " url)))))
  244. (match (crate->guix-package "foo")
  245. (('package
  246. ('name "rust-foo")
  247. ('version "1.0.0")
  248. ('source ('origin
  249. ('method 'url-fetch)
  250. ('uri ('crate-uri "foo" 'version))
  251. ('file-name ('string-append 'name "-" 'version ".tar.gz"))
  252. ('sha256
  253. ('base32
  254. (? string? hash)))))
  255. ('build-system 'cargo-build-system)
  256. ('arguments
  257. ('quasiquote
  258. ('#:cargo-inputs (("rust-bar" ('unquote rust-bar))))))
  259. ('home-page "http://example.com")
  260. ('synopsis "summary")
  261. ('description "summary")
  262. ('license ('list 'license:expat 'license:asl2.0)))
  263. (string=? test-source-hash hash))
  264. (x
  265. (pk 'fail x #f)))))
  266. (test-assert "cargo-recursive-import"
  267. ;; Replace network resources with sample data.
  268. (mock ((guix http-client) http-fetch
  269. (lambda (url . rest)
  270. (match url
  271. ("https://crates.io/api/v1/crates/root"
  272. (open-input-string test-root-crate))
  273. ("https://crates.io/api/v1/crates/root/1.0.0/download"
  274. (set! test-source-hash
  275. (bytevector->nix-base32-string
  276. (sha256 (string->bytevector "empty file\n" "utf-8"))))
  277. (open-input-string "empty file\n"))
  278. ("https://crates.io/api/v1/crates/root/1.0.0/dependencies"
  279. (open-input-string test-root-dependencies))
  280. ("https://crates.io/api/v1/crates/intermediate-1"
  281. (open-input-string test-intermediate-1-crate))
  282. ("https://crates.io/api/v1/crates/intermediate-1/1.0.0/download"
  283. (set! test-source-hash
  284. (bytevector->nix-base32-string
  285. (sha256 (string->bytevector "empty file\n" "utf-8"))))
  286. (open-input-string "empty file\n"))
  287. ("https://crates.io/api/v1/crates/intermediate-1/1.0.0/dependencies"
  288. (open-input-string test-intermediate-1-dependencies))
  289. ("https://crates.io/api/v1/crates/intermediate-2"
  290. (open-input-string test-intermediate-2-crate))
  291. ("https://crates.io/api/v1/crates/intermediate-2/1.0.0/download"
  292. (set! test-source-hash
  293. (bytevector->nix-base32-string
  294. (sha256 (string->bytevector "empty file\n" "utf-8"))))
  295. (open-input-string "empty file\n"))
  296. ("https://crates.io/api/v1/crates/intermediate-2/1.0.0/dependencies"
  297. (open-input-string test-intermediate-2-dependencies))
  298. ("https://crates.io/api/v1/crates/leaf-alice"
  299. (open-input-string test-leaf-alice-crate))
  300. ("https://crates.io/api/v1/crates/leaf-alice/1.0.0/download"
  301. (set! test-source-hash
  302. (bytevector->nix-base32-string
  303. (sha256 (string->bytevector "empty file\n" "utf-8"))))
  304. (open-input-string "empty file\n"))
  305. ("https://crates.io/api/v1/crates/leaf-alice/1.0.0/dependencies"
  306. (open-input-string test-leaf-alice-dependencies))
  307. ("https://crates.io/api/v1/crates/leaf-bob"
  308. (open-input-string test-leaf-bob-crate))
  309. ("https://crates.io/api/v1/crates/leaf-bob/1.0.0/download"
  310. (set! test-source-hash
  311. (bytevector->nix-base32-string
  312. (sha256 (string->bytevector "empty file\n" "utf-8"))))
  313. (open-input-string "empty file\n"))
  314. ("https://crates.io/api/v1/crates/leaf-bob/1.0.0/dependencies"
  315. (open-input-string test-leaf-bob-dependencies))
  316. (_ (error "Unexpected URL: " url)))))
  317. (match (crate-recursive-import "root")
  318. ;; rust-intermediate-2 has no dependency on the rust-leaf-alice package, so this is a valid ordering
  319. ((('package
  320. ('name "rust-leaf-alice")
  321. ('version (? string? ver))
  322. ('source
  323. ('origin
  324. ('method 'url-fetch)
  325. ('uri ('crate-uri "leaf-alice" 'version))
  326. ('file-name
  327. ('string-append 'name "-" 'version ".tar.gz"))
  328. ('sha256
  329. ('base32
  330. (? string? hash)))))
  331. ('build-system 'cargo-build-system)
  332. ('home-page "http://example.com")
  333. ('synopsis "summary")
  334. ('description "summary")
  335. ('license ('list 'license:expat 'license:asl2.0)))
  336. ('package
  337. ('name "rust-leaf-bob")
  338. ('version (? string? ver))
  339. ('source
  340. ('origin
  341. ('method 'url-fetch)
  342. ('uri ('crate-uri "leaf-bob" 'version))
  343. ('file-name
  344. ('string-append 'name "-" 'version ".tar.gz"))
  345. ('sha256
  346. ('base32
  347. (? string? hash)))))
  348. ('build-system 'cargo-build-system)
  349. ('home-page "http://example.com")
  350. ('synopsis "summary")
  351. ('description "summary")
  352. ('license ('list 'license:expat 'license:asl2.0)))
  353. ('package
  354. ('name "rust-intermediate-2")
  355. ('version (? string? ver))
  356. ('source
  357. ('origin
  358. ('method 'url-fetch)
  359. ('uri ('crate-uri "intermediate-2" 'version))
  360. ('file-name
  361. ('string-append 'name "-" 'version ".tar.gz"))
  362. ('sha256
  363. ('base32
  364. (? string? hash)))))
  365. ('build-system 'cargo-build-system)
  366. ('arguments
  367. ('quasiquote
  368. ('#:cargo-inputs (("rust-leaf-bob" ('unquote rust-leaf-bob))))))
  369. ('home-page "http://example.com")
  370. ('synopsis "summary")
  371. ('description "summary")
  372. ('license ('list 'license:expat 'license:asl2.0)))
  373. ('package
  374. ('name "rust-intermediate-1")
  375. ('version (? string? ver))
  376. ('source
  377. ('origin
  378. ('method 'url-fetch)
  379. ('uri ('crate-uri "intermediate-1" 'version))
  380. ('file-name
  381. ('string-append 'name "-" 'version ".tar.gz"))
  382. ('sha256
  383. ('base32
  384. (? string? hash)))))
  385. ('build-system 'cargo-build-system)
  386. ('arguments
  387. ('quasiquote
  388. ('#:cargo-inputs (("rust-intermediate-2" ('unquote rust-intermediate-2))
  389. ("rust-leaf-alice" ('unquote rust-leaf-alice))
  390. ("rust-leaf-bob" ('unquote rust-leaf-bob))))))
  391. ('home-page "http://example.com")
  392. ('synopsis "summary")
  393. ('description "summary")
  394. ('license ('list 'license:expat 'license:asl2.0)))
  395. ('package
  396. ('name "rust-root")
  397. ('version (? string? ver))
  398. ('source
  399. ('origin
  400. ('method 'url-fetch)
  401. ('uri ('crate-uri "root" 'version))
  402. ('file-name
  403. ('string-append 'name "-" 'version ".tar.gz"))
  404. ('sha256
  405. ('base32
  406. (? string? hash)))))
  407. ('build-system 'cargo-build-system)
  408. ('arguments
  409. ('quasiquote
  410. ('#:cargo-inputs (("rust-intermediate-1" ('unquote rust-intermediate-1))
  411. ("rust-intermediate-2" ('unquote rust-intermediate-2))
  412. ("rust-leaf-alice" ('unquote rust-leaf-alice))
  413. ("rust-leaf-bob" ('unquote rust-leaf-bob))))))
  414. ('home-page "http://example.com")
  415. ('synopsis "summary")
  416. ('description "summary")
  417. ('license ('list 'license:expat 'license:asl2.0))))
  418. #t)
  419. (x
  420. (pk 'fail x #f)))))
  421. (test-equal "licenses: MIT OR Apache-2.0"
  422. '(license:expat license:asl2.0)
  423. (string->license "MIT OR Apache-2.0"))
  424. (test-equal "licenses: Apache-2.0 / MIT"
  425. '(license:asl2.0 license:expat)
  426. (string->license "Apache-2.0 / MIT"))
  427. (test-equal "licenses: Apache-2.0 WITH LLVM-exception"
  428. '(license:asl2.0 unknown-license!)
  429. (string->license "Apache-2.0 WITH LLVM-exception"))
  430. (test-equal "licenses: MIT/Apache-2.0 AND BSD-2-Clause"
  431. '(license:expat license:asl2.0 unknown-license!)
  432. (string->license "MIT/Apache-2.0 AND BSD-2-Clause"))
  433. (test-equal "licenses: MIT/Apache-2.0"
  434. '(license:expat license:asl2.0)
  435. (string->license "MIT/Apache-2.0"))
  436. (test-end "crate")