guix-package.el 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. ;;; guix-package.el --- Guix packages -*- lexical-binding: t -*-
  2. ;; Copyright © 2014–2019 Alex Kost <alezost@gmail.com>
  3. ;; This file is part of Emacs-Guix.
  4. ;; Emacs-Guix is free software; you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  8. ;;
  9. ;; Emacs-Guix is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with Emacs-Guix. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This file provides a general code related to Guix package.
  18. ;;; Code:
  19. (require 'cl-lib)
  20. (require 'guix-read)
  21. (require 'guix-repl)
  22. (require 'guix-guile)
  23. (require 'guix-location)
  24. (require 'guix-misc)
  25. (defun guix-package-name-specification (name version &optional output)
  26. "Return Guix package specification by its NAME, VERSION and OUTPUT."
  27. (concat name "@" version
  28. (when output (concat ":" output))))
  29. (defun guix-package-id-and-output-by-output-id (output-id)
  30. "Return a list (PACKAGE-ID OUTPUT) by OUTPUT-ID."
  31. (cl-multiple-value-bind (package-id-str output)
  32. (split-string output-id ":")
  33. (let ((package-id (string-to-number package-id-str)))
  34. (list (if (= 0 package-id) package-id-str package-id)
  35. output))))
  36. (defun guix-package-build-log-file (id)
  37. "Return build log file name of a package defined by ID."
  38. (guix-eval-read
  39. (guix-make-guile-expression 'package-build-log-file id)))
  40. (declare-function guix-build-log-find-file "guix-build-log" (file))
  41. (defun guix-package-find-build-log (id)
  42. "Show build log of a package defined by ID."
  43. (require 'guix-build-log)
  44. (let ((file (guix-package-build-log-file id)))
  45. (if file
  46. (guix-build-log-find-file file)
  47. (message "Couldn't find the package build log."))))
  48. (defun guix-package-source-file-name (package-id)
  49. "Return a store file name to a source of a package PACKAGE-ID."
  50. (message "Calculating the source derivation ...")
  51. (guix-eval-read
  52. (guix-make-guile-expression
  53. 'package-source-file-name package-id)))
  54. (defun guix-package-store-path (package-id)
  55. "Return a list of store directories of outputs of package PACKAGE-ID."
  56. (message "Calculating the package derivation ...")
  57. (guix-eval-read
  58. (guix-make-guile-expression
  59. 'package-store-path package-id)))
  60. (defvar guix-after-source-download-hook nil
  61. "Hook run after successful performing a 'source-download' operation.")
  62. (defun guix-package-source-build-derivation (package-id &optional prompt)
  63. "Build source derivation of a package PACKAGE-ID.
  64. Ask a user with PROMPT for continuing an operation."
  65. (when (or (not guix-operation-confirm)
  66. (guix-operation-prompt (or prompt
  67. "Build the source derivation?")))
  68. (guix-eval-in-repl
  69. (guix-make-guile-expression
  70. 'package-source-build-derivation
  71. package-id
  72. :use-substitutes? (or guix-use-substitutes 'f)
  73. :dry-run? (or guix-dry-run 'f))
  74. nil 'source-download)))
  75. (defun guix-build-package (package-id &optional prompt)
  76. "Build package with PACKAGE-ID.
  77. Ask a user with PROMPT for continuing the build operation."
  78. (when (or (not guix-operation-confirm)
  79. (guix-operation-prompt (or prompt "Build package?")))
  80. (guix-eval-in-repl
  81. (format (concat "(build-package* (package-by-id %d)"
  82. " #:use-substitutes? %s"
  83. " #:dry-run? %s)")
  84. package-id
  85. (guix-guile-boolean guix-use-substitutes)
  86. (guix-guile-boolean guix-dry-run)))))
  87. (defun guix-read-package-size-type ()
  88. "Prompt a user for a package size type."
  89. (intern
  90. (completing-read "Size type (\"text\" or \"image\"): "
  91. '("text" "image")
  92. nil t nil nil "text")))
  93. ;;;###autoload
  94. (defun guix-package-size (package-or-file &optional type)
  95. "Show size of PACKAGE-OR-FILE.
  96. PACKAGE-OR-FILE should be either a package name or a store file name.
  97. TYPE should be on of the following symbols: `text' (default) or `image'.
  98. Interactively, prompt for a package name and size TYPE."
  99. (interactive
  100. (list (guix-read-package-name)
  101. (guix-read-package-size-type)))
  102. (cl-case (or type 'text)
  103. (text (guix-eval-in-repl
  104. (guix-make-guile-expression
  105. 'guix-command "size" package-or-file)))
  106. (image (let ((map-file (guix-png-file-name)))
  107. (guix-command-output
  108. (list "size"
  109. (concat "--map-file=" map-file)
  110. package-or-file))
  111. (if (file-exists-p map-file)
  112. (guix-find-file map-file)
  113. (error "\
  114. Couldn't create an image file.
  115. Please check 'guix size' shell command to make sure it works"))))
  116. (t (error "Unknown size type (should be `image' or `text'): %S"
  117. type))))
  118. ;;;###autoload
  119. (defun guix-package-lint (packages &optional checkers)
  120. "Lint PACKAGES using CHECKERS.
  121. PACKAGES is a list of package names.
  122. CHECKERS is a list of checker names; if nil, use all checkers.
  123. Interactively, prompt for PACKAGES and use all checkers.
  124. With prefix argument, also prompt for checkers (should be comma
  125. separated).
  126. See Info node `(guix) Invoking guix lint' for details about linting."
  127. (interactive
  128. (list (guix-read-package-names)
  129. (and current-prefix-arg
  130. (guix-read-lint-checker-names))))
  131. (guix-eval-in-repl
  132. (guix-make-guile-expression
  133. 'lint-packages packages checkers)))
  134. ;;;###autoload
  135. (defalias 'guix-lint 'guix-package-lint)
  136. ;;;###autoload
  137. (defun guix-find-package-location-file (file &optional directory)
  138. "Open package location FILE.
  139. See `guix-find-location' for the meaning of DIRECTORY.
  140. Interactively, prompt for the location FILE. With prefix
  141. argument, prompt for DIRECTORY as well."
  142. (interactive
  143. (list (guix-read-package-location-file)
  144. (guix-read-directory)))
  145. (guix-find-location file directory))
  146. (defun guix-package-location (id-or-name)
  147. "Return location of a package with ID-OR-NAME.
  148. For the meaning of location, see `guix-find-location'."
  149. (guix-eval-read (guix-make-guile-expression
  150. 'package-location-string id-or-name)))
  151. ;;;###autoload
  152. (defun guix-find-package-definition (id-or-name &optional directory)
  153. "Go to the location of package with ID-OR-NAME.
  154. See `guix-find-location' for the meaning of package location and
  155. DIRECTORY.
  156. Interactively, with prefix argument, prompt for DIRECTORY."
  157. (interactive
  158. (list (guix-read-package-name)
  159. (guix-read-directory)))
  160. (let ((loc (guix-package-location id-or-name)))
  161. (if loc
  162. (guix-find-location loc directory)
  163. (message "Couldn't find package location."))))
  164. ;;;###autoload
  165. (defalias 'guix-edit 'guix-find-package-definition)
  166. (provide 'guix-package)
  167. ;;; guix-package.el ends here