json.scm 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2014 David Thompson <davet@gnu.org>
  3. ;;; Copyright © 2015, 2016 Eric Bavier <bavier@member.fsf.org>
  4. ;;; Copyright © 2018, 2019 Ludovic Courtès <ludo@gnu.org>
  5. ;;; Copyright © 2020 Ricardo Wurmus <rekado@elephly.net>
  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 (guix import json)
  22. #:use-module (json)
  23. #:use-module (guix http-client)
  24. #:use-module (guix import utils)
  25. #:use-module (guix import print)
  26. #:use-module (ice-9 match)
  27. #:use-module (ice-9 rdelim)
  28. #:use-module (srfi srfi-1)
  29. #:use-module (srfi srfi-2)
  30. #:use-module (srfi srfi-26)
  31. #:use-module (srfi srfi-34)
  32. #:export (json-fetch
  33. json->code
  34. json->scheme-file))
  35. (define* (json-fetch url
  36. #:key
  37. (http-fetch http-fetch)
  38. ;; Note: many websites returns 403 if we omit a
  39. ;; 'User-Agent' header.
  40. (headers `((user-agent . "GNU Guile")
  41. (Accept . "application/json"))))
  42. "Return a representation of the JSON resource URL (a list or hash table), or
  43. #f if URL returns 403 or 404. HEADERS is a list of HTTP headers to pass in
  44. the query. HTTP-FETCH is called to perform the request: for example, to
  45. enable caching, supply 'http-fetch/cached'."
  46. (guard (c ((and (http-get-error? c)
  47. (let ((error (http-get-error-code c)))
  48. (or (= 403 error)
  49. (= 404 error))))
  50. #f))
  51. (let* ((port (http-fetch url #:headers headers))
  52. (result (json->scm port)))
  53. (close-port port)
  54. result)))
  55. (define (json->code file-name)
  56. "Read FILE-NAME containing one ore more JSON package definitions and return
  57. a list of S-expressions, or return #F when the JSON is invalid."
  58. (catch 'json-invalid
  59. (lambda ()
  60. (let ((json (json-string->scm
  61. (with-input-from-file file-name read-string))))
  62. (match json
  63. (#(packages ...)
  64. ;; To allow definitions to refer to one another, collect references
  65. ;; to local definitions and tell alist->package to ignore them.
  66. (second
  67. (memq #:result
  68. (fold
  69. (lambda (pkg names+result)
  70. (match names+result
  71. ((#:names names #:result result)
  72. (list #:names
  73. (cons (assoc-ref pkg "name") names)
  74. #:result
  75. (append result
  76. (list
  77. (package->code (alist->package pkg names))
  78. (string->symbol (assoc-ref pkg "name"))))))))
  79. (list #:names '()
  80. #:result '())
  81. packages))))
  82. (package
  83. (list (package->code (alist->package json))
  84. (string->symbol (assoc-ref json "name")))))))
  85. (const #f)))
  86. (define (json->scheme-file file)
  87. "Convert the FILE containing a JSON package definition to a Scheme
  88. representation and return the new file name (or #F on error)."
  89. (and-let* ((sexprs (json->code file))
  90. (file* (let* ((tempdir (or (getenv "TMPDIR") "/tmp"))
  91. (template (string-append tempdir "/guix-XXXXXX"))
  92. (port (mkstemp! template)))
  93. (close-port port)
  94. template)))
  95. (call-with-output-file file*
  96. (lambda (port)
  97. (write '(use-modules (gnu)
  98. (guix)
  99. ((guix licenses) #:prefix license:))
  100. port)
  101. (for-each (cut write <> port) sexprs)))
  102. file*))