guix-ui-package.el 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722
  1. ;;; guix-ui-package.el --- Interface for displaying packages -*- lexical-binding: t -*-
  2. ;; Copyright © 2014–2019, 2021 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 an interface for displaying packages and outputs
  18. ;; in 'list' and 'info' buffers, and commands for working with them.
  19. ;;; Code:
  20. (require 'cl-lib)
  21. (require 'dash)
  22. (require 'bui)
  23. (require 'guix nil t)
  24. (require 'guix-ui)
  25. (require 'guix-ui-store-item)
  26. (require 'guix-misc)
  27. (require 'guix-repl)
  28. (require 'guix-guile)
  29. (require 'guix-utils)
  30. (require 'guix-read)
  31. (require 'guix-license)
  32. (require 'guix-location)
  33. (require 'guix-package)
  34. (require 'guix-profiles)
  35. (guix-ui-define-entry-type package)
  36. (guix-ui-define-entry-type output)
  37. (defcustom guix-package-list-type 'output
  38. "Define how to display packages in 'list' buffer.
  39. Should be a symbol `package' or `output' (if `output', display each
  40. output on a separate line; if `package', display each package on
  41. a separate line)."
  42. :type '(choice (const :tag "List of packages" package)
  43. (const :tag "List of outputs" output))
  44. :group 'guix-package)
  45. (defcustom guix-package-use-name-at-point t
  46. "If non-nil, \\[guix-packages-by-name] uses symbol at point as default
  47. if it is a package name.
  48. If nil, then no default name is used."
  49. :type 'boolean
  50. :group 'guix-package)
  51. (defun guix-package-list-type ()
  52. "Return BUI list entry-type by `guix-package-list-type' variable."
  53. (guix-make-symbol guix-package-list-type))
  54. ;; To avoid compilation warning: this variable is actually defined later
  55. ;; along with the rest "package-list" interface stuff.
  56. (defvar guix-package-list-show-single)
  57. (defun guix-package-get-display (profile search-type &rest search-values)
  58. "Search for packages/outputs and show results.
  59. If PROFILE is nil, use `guix-current-profile'.
  60. See `guix-ui-get-entries' for the meaning of SEARCH-TYPE and
  61. SEARCH-VALUES.
  62. Results are displayed in the list buffer, unless a single package
  63. is found and `guix-package-list-show-single' is nil."
  64. (let* ((args (cl-list* (guix-package-profile
  65. (or profile guix-current-profile))
  66. search-type search-values))
  67. (entries (bui-get-entries (guix-package-list-type) 'list args)))
  68. (if (or guix-package-list-show-single
  69. (null entries)
  70. (cdr entries))
  71. (bui-display-entries entries (guix-package-list-type) 'list args)
  72. (bui-get-display-entries 'guix-package 'info args))))
  73. (defun guix-package-entry->name-specification (entry &optional output)
  74. "Return name specification of the package ENTRY and OUTPUT."
  75. (guix-package-name-specification
  76. (bui-entry-non-void-value entry 'name)
  77. (bui-entry-non-void-value entry 'version)
  78. (or output (bui-entry-non-void-value entry 'output))))
  79. (defun guix-package-entries->name-specifications (entries)
  80. "Return name specifications by the package or output ENTRIES."
  81. (cl-remove-duplicates (mapcar #'guix-package-entry->name-specification
  82. entries)
  83. :test #'string=))
  84. (defun guix-package-entry-installed-outputs (entry)
  85. "Return a list of installed outputs for the package ENTRY."
  86. (--map (bui-entry-non-void-value it 'output)
  87. (bui-entry-non-void-value entry 'installed)))
  88. (defun guix-read-package-name-from-entries (entries)
  89. "Prompt for a package name and return it.
  90. Names are completed from package ENTRIES."
  91. (completing-read "Package: "
  92. (--map (bui-entry-value it 'name) entries)))
  93. (defun guix-read-package-entry-by-name (&optional entries)
  94. "Return an entry from package ENTRIES (current entries by default).
  95. If there is only one entry, return it. If there are multiple
  96. entries, prompt for a package name and return an entry with this
  97. name."
  98. (or entries (setq entries (bui-current-entries)))
  99. ;; There is unavoidable (?) downside: when there are several packages
  100. ;; with the same name, they cannot be distinguished, so the first one
  101. ;; from ENTRIES will be returned.
  102. (pcase entries
  103. (`(,entry) entry)
  104. (_ (bui-entry-by-param entries 'name
  105. (guix-read-package-name-from-entries entries)))))
  106. (defun guix-read-package-output (outputs)
  107. "Return an output from package OUTPUTS.
  108. If there is only one output, return it. If there are multiple
  109. OUTPUTS, prompt for it."
  110. (or outputs
  111. (error "No package outputs!"))
  112. (if (cdr outputs)
  113. (completing-read "Output: " outputs nil t)
  114. (car outputs)))
  115. (defun guix-read-package-entry-and-output (&optional entries)
  116. "Return a list with package entry and output.
  117. See `guix-read-package-entry-by-name' and
  118. `guix-read-package-output' for details."
  119. (let* ((entry (guix-read-package-entry-by-name entries))
  120. (outputs (bui-entry-non-void-value entry 'outputs))
  121. (output (guix-read-package-output outputs)))
  122. (list entry output)))
  123. ;;; Processing package actions
  124. (defvar guix-package-name-width 40
  125. "Width of a package name \"column\".
  126. This variable is used in a buffer to confirm operation.")
  127. (defun guix-process-package-actions (profile actions
  128. &optional operation-buffer)
  129. "Process package ACTIONS on PROFILE.
  130. Each action is a list of the form:
  131. (ACTION-TYPE PACKAGE-SPEC ...)
  132. ACTION-TYPE is one of the following symbols: `install',
  133. `upgrade', `remove'/`delete'.
  134. PACKAGE-SPEC should have the following form: (ID [OUTPUT] ...)."
  135. (let (install upgrade remove)
  136. (mapc (lambda (action)
  137. (let ((action-type (car action))
  138. (specs (cdr action)))
  139. (cl-case action-type
  140. (install (setq install (append install specs)))
  141. (upgrade (setq upgrade (append upgrade specs)))
  142. ((remove delete) (setq remove (append remove specs))))))
  143. actions)
  144. (when (guix-continue-package-operation-p
  145. profile
  146. :install install :upgrade upgrade :remove remove)
  147. (guix-eval-in-repl
  148. (guix-make-guile-expression
  149. 'process-package-actions profile
  150. :install install :upgrade upgrade :remove remove
  151. :use-substitutes? (or guix-use-substitutes 'f)
  152. :dry-run? (or guix-dry-run 'f))
  153. (and (not guix-dry-run) operation-buffer)))))
  154. (cl-defun guix-continue-package-operation-p (profile
  155. &key install upgrade remove)
  156. "Return non-nil if a package operation should be continued.
  157. Ask a user if needed (see `guix-operation-confirm').
  158. INSTALL, UPGRADE, REMOVE are 'package action specifications'.
  159. See `guix-process-package-actions' for details."
  160. (or (null guix-operation-confirm)
  161. (let* ((entries (guix-ui-get-entries
  162. profile 'package 'id
  163. (append (mapcar #'car install)
  164. (mapcar #'car upgrade)
  165. (mapcar #'car remove))
  166. '(id name version location)))
  167. (install-strings (guix-get-package-strings install entries))
  168. (upgrade-strings (guix-get-package-strings upgrade entries))
  169. (remove-strings (guix-get-package-strings remove entries)))
  170. (if (or install-strings upgrade-strings remove-strings)
  171. (let ((buf (get-buffer-create guix-temp-buffer-name)))
  172. (with-current-buffer buf
  173. (setq-local cursor-type nil)
  174. (setq buffer-read-only nil)
  175. (erase-buffer)
  176. (insert (propertize "Profile" 'face 'bold)
  177. ": " profile "\n\n")
  178. (guix-insert-package-strings install-strings "install")
  179. (guix-insert-package-strings upgrade-strings "upgrade")
  180. (guix-insert-package-strings remove-strings "remove")
  181. (let ((win (temp-buffer-window-show
  182. buf
  183. '((display-buffer-reuse-window
  184. display-buffer-at-bottom)
  185. (window-height . fit-window-to-buffer)))))
  186. (prog1 (guix-operation-prompt)
  187. (quit-window nil win)))))
  188. (message "Nothing to be done.
  189. If Guix REPL was restarted, the data is not up-to-date.")
  190. nil))))
  191. (defun guix-get-package-strings (specs entries)
  192. "Return short package descriptions for performing package actions.
  193. See `guix-process-package-actions' for the meaning of SPECS.
  194. ENTRIES is a list of package entries to get info about packages."
  195. (-non-nil
  196. (-map (-lambda ((id . outputs))
  197. (--when-let (bui-entry-by-id entries id)
  198. (let ((location (bui-entry-non-void-value it 'location))
  199. (name (guix-package-entry->name-specification it)))
  200. (with-temp-buffer
  201. (insert name)
  202. (when outputs
  203. (insert ":" (guix-concat-strings outputs ",")))
  204. (when location
  205. (indent-to guix-package-name-width 2)
  206. (insert "(" location ")"))
  207. (buffer-string)))))
  208. specs)))
  209. (defun guix-insert-package-strings (strings action)
  210. "Insert information STRINGS at point for performing package ACTION."
  211. (when strings
  212. (insert "Package(s) to " (propertize action 'face 'bold) ":\n")
  213. (dolist (str strings)
  214. (insert " " str "\n"))
  215. (bui-newline)))
  216. ;;; Package 'info'
  217. (guix-ui-define-interface package info
  218. :mode-name "Package-Info"
  219. :buffer-name "*Guix Package Info*"
  220. :get-entries-function 'guix-package-info-get-entries
  221. :format '(guix-package-info-insert-heading
  222. nil
  223. guix-package-info-insert-additional-text
  224. (synopsis nil (simple guix-package-info-synopsis))
  225. nil
  226. (description nil (simple guix-package-info-description))
  227. nil
  228. (outputs simple guix-package-info-insert-outputs)
  229. guix-package-info-insert-misc
  230. (source simple guix-package-info-insert-source)
  231. (location simple guix-package-info-insert-location)
  232. (upstream-name format (format))
  233. (home-url format (format bui-url))
  234. (license format (format guix-package-license))
  235. (systems format guix-package-info-insert-systems)
  236. (inputs format (guix-package-info-insert-name-buttons
  237. guix-package-input))
  238. (native-inputs format (guix-package-info-insert-name-buttons
  239. guix-package-native-input))
  240. (propagated-inputs format (guix-package-info-insert-name-buttons
  241. guix-package-propagated-input)))
  242. :hint 'guix-package-info-hint
  243. :titles '((home-url . "Home page")
  244. (systems . "Supported systems"))
  245. :required '(id name version installed non-unique known-status
  246. superseded hidden))
  247. ;; Additional info for installed outputs.
  248. (bui-define-interface guix-installed-output info
  249. :format '((file-name simple (guix-info-insert-store-items))
  250. (dependencies simple (guix-info-insert-store-items)))
  251. :titles '((file-name . "Store directory"))
  252. :reduced? t)
  253. ;; Additional info for "guix pull"-ed 'guix' package.
  254. (bui-define-interface guix-pulled-package info
  255. :format '((url format (format bui-url))
  256. (branch format (format))
  257. (commit format (format)))
  258. :reduced? t)
  259. (let ((map guix-package-info-mode-map))
  260. (define-key map (kbd "i") 'guix-package-info-install)
  261. (define-key map (kbd "d") 'guix-package-info-delete)
  262. (define-key map (kbd "U") 'guix-package-info-upgrade)
  263. (define-key map (kbd "u") 'guix-package-info-upgrade)
  264. (define-key map (kbd "e") 'guix-package-info-edit)
  265. (define-key map (kbd "G") 'guix-package-info-graph)
  266. (define-key map (kbd "z") 'guix-package-info-size)
  267. (define-key map (kbd "L") 'guix-package-info-lint))
  268. (defvar guix-package-info-default-hint
  269. '(("\\[guix-package-info-edit]") " edit (go to) the package definition;\n"
  270. ("\\[guix-package-info-graph]") " view package graph; "
  271. ("\\[guix-package-info-size]") " view package size; "
  272. ("\\[guix-package-info-lint]") " lint;\n"
  273. ("\\[guix-package-info-install]") " install; "
  274. ("\\[guix-package-info-delete]") " delete; "
  275. ("\\[guix-package-info-upgrade]") " upgrade;\n"))
  276. (defun guix-package-info-hint ()
  277. (bui-format-hints
  278. guix-package-info-default-hint
  279. guix-ui-hint
  280. (bui-default-hint)))
  281. (defface guix-package-info-heading
  282. '((t :inherit bui-info-heading))
  283. "Face for package name and version headings."
  284. :group 'guix-package-info-faces)
  285. (defface guix-package-info-name-button
  286. '((t :inherit button))
  287. "Face used for a full name that can be used to describe a package."
  288. :group 'guix-package-info-faces)
  289. ;; Currently, `guix-package-info-name' and `guix-package-info-version'
  290. ;; faces are not used, but they were in the past and may be used in
  291. ;; future, so they were not removed.
  292. (defface guix-package-info-name
  293. '((t :inherit font-lock-keyword-face))
  294. "Face used for a name of a package."
  295. :group 'guix-package-info-faces)
  296. (defface guix-package-info-version
  297. '((t :inherit font-lock-builtin-face))
  298. "Face used for a version of a package."
  299. :group 'guix-package-info-faces)
  300. (defface guix-package-info-synopsis
  301. '((((type tty pc) (class color)) :weight bold)
  302. (t :height 1.1 :weight bold :inherit variable-pitch))
  303. "Face used for a synopsis of a package."
  304. :group 'guix-package-info-faces)
  305. (defface guix-package-info-description
  306. '((t :inherit font-lock-doc-face))
  307. "Face used for a description of a package."
  308. :group 'guix-package-info-faces)
  309. (defface guix-package-info-license
  310. '((t :inherit font-lock-string-face))
  311. "Face used for a license of a package."
  312. :group 'guix-package-info-faces)
  313. (defface guix-package-info-source
  314. '((t :inherit bui-url :underline nil))
  315. "Face used for a source URL of a package."
  316. :group 'guix-package-info-faces)
  317. (defface guix-package-info-installed-outputs
  318. '((t :inherit guix-true))
  319. "Face used for installed outputs of a package."
  320. :group 'guix-package-info-faces)
  321. (defface guix-package-info-uninstalled-outputs
  322. '((t :inherit guix-false))
  323. "Face used for uninstalled outputs of a package."
  324. :group 'guix-package-info-faces)
  325. (defface guix-package-info-unknown
  326. '((t :inherit error))
  327. "Face used for unknown packages.
  328. 'Unknown' means there are no packages with this name among Guix
  329. packages. Perhaps you installed this package in the past, and it
  330. was renamed later."
  331. :group 'guix-package-info-faces)
  332. (defface guix-package-info-obsolete
  333. '((t :inherit font-lock-warning-face))
  334. "Face used for obsolete packages.
  335. 'Obsolete' means there is a Guix package with this name but with
  336. a newer version (probably it's time to update)."
  337. :group 'guix-package-info-faces)
  338. (defface guix-package-info-future
  339. '((default :inherit guix-package-info-installed-outputs)
  340. (((class color) (min-colors 88) (background light))
  341. :foreground "RoyalBlue3")
  342. (((class color) (min-colors 88) (background dark))
  343. :foreground "DeepSkyBlue")
  344. (((class color) (min-colors 8))
  345. :foreground "blue"))
  346. "Face used for packages from the future.
  347. 'From the future' means there is a Guix package with this name
  348. but with an older version, i.e. the installed package is newer
  349. than available from Guix! This is rather unusual, it may happen,
  350. for example, if you installed a package after 'guix pull' (see
  351. Info node `(guix) Invoking guix pull') and then you removed the
  352. pulled directory, so Guix searches for packages in its original
  353. directory with the old package recipes."
  354. :group 'guix-package-info-faces)
  355. (defface guix-package-info-superseded
  356. '((t :inherit shadow))
  357. "Face used for superseded packages."
  358. :group 'guix-package-info-faces)
  359. (defface guix-package-info-hidden
  360. '((t :inherit shadow))
  361. "Face used for hidden packages.
  362. Most likely you will never see these packages (because they are
  363. hidden and hard to find), so you may not bother customizing this
  364. face."
  365. :group 'guix-package-info-faces)
  366. (defcustom guix-package-info-auto-find-package t
  367. "If non-nil, open store directory after pressing \"Show\" package button.
  368. If nil, just display the store directory (or directories) without finding."
  369. :type 'boolean
  370. :group 'guix-package-info)
  371. (defcustom guix-package-info-auto-find-source nil
  372. "If non-nil, open source file after pressing \"Show\" source button.
  373. If nil, just display the source file name without finding."
  374. :type 'boolean
  375. :group 'guix-package-info)
  376. (defcustom guix-package-info-auto-download-source t
  377. "If nil, do not automatically download a source file if it doesn't exist.
  378. After pressing a \"Show\" button, a derivation of the package
  379. source is calculated and a store file name is displayed. If this
  380. variable is non-nil and the source file does not exist in the
  381. store, it will be automatically downloaded (with a possible
  382. prompt depending on `guix-operation-confirm' variable)."
  383. :type 'boolean
  384. :group 'guix-package-info)
  385. (defcustom guix-package-info-button-functions
  386. '(guix-package-info-insert-build-button
  387. guix-package-info-insert-build-log-button
  388. guix-package-info-insert-graph-button
  389. guix-package-info-insert-size-button
  390. guix-package-info-insert-lint-button)
  391. "List of functions used to insert package buttons in Info buffer.
  392. Each function is called with 2 arguments: package ID and full name."
  393. :type '(repeat function)
  394. :group 'guix-package-info)
  395. (defvar guix-package-info-download-buffer nil
  396. "Buffer from which a current download operation was performed.")
  397. (defvar guix-package-info-output-format "%-8s "
  398. "String used to format output names of the packages.
  399. It should be a '%s'-sequence. After inserting an output name
  400. formatted with this string, an action button is inserted.")
  401. (define-button-type 'guix-package-license
  402. :supertype 'bui
  403. 'face 'guix-package-info-license
  404. 'help-echo "Display license info"
  405. 'action (lambda (btn)
  406. (require 'guix-ui-license)
  407. (bui-get-display-entries
  408. 'guix-license 'info
  409. (list 'name (button-label btn))
  410. 'add)))
  411. (defun guix-package-button-action (button)
  412. "Display package info for package BUTTON."
  413. (let ((search-type 'id)
  414. (search-value (or (button-get button 'id)
  415. (button-get button 'spec)
  416. (button-label button))))
  417. (if (eq major-mode 'guix-package-info-mode)
  418. (bui-get-display-entries-current
  419. 'guix-package 'info
  420. (list (guix-ui-current-profile)
  421. search-type search-value))
  422. (bui-get-display-entries
  423. 'guix-package 'info
  424. (list guix-current-profile
  425. search-type search-value)))))
  426. (define-button-type 'guix-package-name
  427. :supertype 'bui
  428. 'face 'guix-package-info-name-button
  429. 'help-echo "Describe this package"
  430. 'action 'guix-package-button-action)
  431. (define-button-type 'guix-package-heading
  432. :supertype 'guix-package-name
  433. 'face 'guix-package-info-heading)
  434. (define-button-type 'guix-package-source
  435. :supertype 'bui
  436. 'face 'guix-package-info-source
  437. 'help-echo ""
  438. 'action (lambda (_)
  439. ;; As a source may not be a real URL (e.g., "mirror://..."),
  440. ;; no action is bound to a source button.
  441. (message "Yes, this is the source URL. What did you expect?")))
  442. (defun guix-package-info-get-entries (profile search-type
  443. &rest search-values)
  444. "Return 'package' entries for displaying them in 'info' buffer."
  445. (guix-eval-read
  446. (guix-make-guile-expression
  447. 'package/output-sexps
  448. profile 'package search-type search-values
  449. (cl-union guix-package-info-required-params
  450. (bui-info-displayed-params 'guix-package)))))
  451. (defun guix-package-info-insert-heading (entry)
  452. "Insert package ENTRY heading (name and version) at point."
  453. (bui-insert-button
  454. (concat (bui-entry-non-void-value entry 'name) " "
  455. (bui-entry-non-void-value entry 'version))
  456. 'guix-package-heading
  457. 'spec (guix-package-entry->name-specification entry))
  458. (bui-newline))
  459. (defun guix-package-info-insert-location (location &optional _)
  460. "Insert package LOCATION at point."
  461. (bui-insert-non-nil location
  462. (bui-info-insert-value-indent location 'guix-location)
  463. (let ((location-file (guix-location-file location)))
  464. ;; Do not show "Packages" button if a package 'from file' is displayed.
  465. (unless (eq (guix-ui-current-search-type) 'from-file)
  466. (bui-insert-indent)
  467. (bui-insert-action-button
  468. "Packages"
  469. (lambda (btn)
  470. (guix-package-get-display (guix-ui-current-profile)
  471. 'location
  472. (button-get btn 'location)))
  473. (format "Display packages from location '%s'" location-file)
  474. 'location location-file)))))
  475. (defun guix-package-info-insert-systems (systems entry)
  476. "Insert supported package SYSTEMS at point."
  477. (if (require 'build-farm-build nil t)
  478. (bui-info-insert-value-format
  479. systems 'build-farm-system
  480. 'job (build-farm-job-name-specification
  481. (bui-entry-non-void-value entry 'name)
  482. (bui-entry-non-void-value entry 'version)))
  483. (bui-info-insert-value-format systems)))
  484. (defmacro guix-package-info-define-insert-inputs (&optional type)
  485. "Define a face and a button for package inputs.
  486. TYPE is a type of inputs.
  487. Button name is `guix-package-TYPE-input'.
  488. Face name is `guix-package-info-TYPE-inputs'."
  489. (let* ((type-str (symbol-name type))
  490. (type-name (and type (concat type-str "-")))
  491. (type-desc (and type (concat type-str " ")))
  492. (face (intern (concat "guix-package-info-" type-name "inputs")))
  493. (btn (intern (concat "guix-package-" type-name "input"))))
  494. `(progn
  495. (defface ,face
  496. '((t :inherit guix-package-info-name-button))
  497. ,(concat "Face used for " type-desc "inputs of a package.")
  498. :group 'guix-package-info-faces)
  499. (define-button-type ',btn
  500. :supertype 'guix-package-name
  501. 'face ',face))))
  502. (guix-package-info-define-insert-inputs)
  503. (guix-package-info-define-insert-inputs native)
  504. (guix-package-info-define-insert-inputs propagated)
  505. (defun guix-package-info-insert-name-buttons (values &optional button)
  506. "Insert package name buttons at point.
  507. Each element from VALUES should either be a specification string
  508. or (id spec) list."
  509. (bui-insert-non-nil values
  510. (let* ((text (with-temp-buffer
  511. (bui-mapinsert
  512. (lambda (value)
  513. (let ((spec (if (listp value)
  514. (cadr value)
  515. value)))
  516. (bui-insert-button
  517. spec (or button 'guix-package-name)
  518. 'id value)))
  519. values
  520. bui-list-separator)
  521. (buffer-substring (point-min) (point-max))))
  522. (strings (bui-split-string
  523. text
  524. (- (bui-fill-column)
  525. (length bui-info-multiline-prefix)))))
  526. (bui-mapinsert #'insert
  527. strings
  528. (concat "\n" bui-info-multiline-prefix)))))
  529. (defun guix-package-info-insert-name-button (value &optional button)
  530. "Insert package name button at point."
  531. (guix-package-info-insert-name-buttons (list value) button))
  532. (defun guix-package-info-insert-outputs (outputs entry)
  533. "Insert OUTPUTS from package ENTRY at point."
  534. (bui-newline)
  535. (dolist (output outputs)
  536. (guix-package-info-insert-output output entry)))
  537. (defun guix-package-info-insert-additional-text (entry)
  538. "Insert some additional info for package ENTRY at point."
  539. (let ((name (bui-entry-non-void-value entry 'name)))
  540. (if (bui-entry-non-void-value entry 'hidden)
  541. (progn
  542. (guix-package-info-insert-hidden-text)
  543. (bui-newline))
  544. (cl-case (bui-entry-non-void-value entry 'known-status)
  545. (known
  546. (when (bui-entry-non-void-value entry 'non-unique)
  547. (guix-package-info-insert-non-unique-text
  548. (guix-package-entry->name-specification entry))
  549. (bui-newline))
  550. (--when-let (bui-entry-non-void-value entry 'superseded)
  551. (guix-package-info-insert-superseded-text it)
  552. (bui-newline)))
  553. (obsolete (guix-package-info-insert-obsolete-text name))
  554. (unknown (guix-package-info-insert-unknown-text name))
  555. (future (guix-package-info-insert-future-text name))
  556. (pull (guix-package-info-insert-pull-text name entry))))))
  557. (defun guix-package-info-insert-unknown-text (name)
  558. "Insert a message about unknown package at point."
  559. (insert "This package is ")
  560. (bui-format-insert "unknown" 'guix-package-info-unknown)
  561. (insert ", i.e. there are no packages with\n"
  562. "'" name "' name among the available package recipes."))
  563. (defun guix-package-info-insert-obsolete-text (name)
  564. "Insert a message about obsolete package NAME at point."
  565. (insert "This package is ")
  566. (bui-format-insert "obsolete" 'guix-package-info-obsolete)
  567. (insert ", i.e. a newer version of\n")
  568. (bui-insert-button name 'guix-package-name)
  569. (insert " package is available."))
  570. (defun guix-package-info-insert-future-text (name)
  571. "Insert a message about package NAME with a future VERSION at point."
  572. (insert "This package is ")
  573. (bui-format-insert "from the future" 'guix-package-info-future)
  574. (insert ", i.e. this (installed) package
  575. is newer than the available package recipe for ")
  576. (bui-insert-button name 'guix-package-name)
  577. (insert "."))
  578. (defun guix-package-info-insert-pull-text (name entry)
  579. "Insert a message that NAME package was 'guix pull'-ed."
  580. (insert "This ")
  581. (bui-insert-button name 'guix-package-name)
  582. (insert " package was installed by 'guix pull' command")
  583. (let ((repository (bui-entry-non-void-value entry 'repository)))
  584. (if (not repository)
  585. (insert ".")
  586. (insert "\nfrom the following repository:\n\n")
  587. (bui-info-insert-entry repository 'guix-pulled-package 1))))
  588. (defun guix-package-info-insert-non-unique-text (full-name)
  589. "Insert a message about non-unique package with FULL-NAME at point."
  590. (insert "Installed outputs are displayed for a non-unique ")
  591. (bui-insert-button full-name 'guix-package-name)
  592. (insert " package.")
  593. (bui-newline))
  594. (defun guix-package-info-insert-superseded-text (full-name)
  595. "Insert a message that current package is superseded by FULL-NAME."
  596. (insert "This package is ")
  597. (bui-format-insert "superseded" 'guix-package-info-superseded)
  598. (insert " by ")
  599. (bui-insert-button full-name 'guix-package-name)
  600. (insert " package.")
  601. (bui-newline))
  602. (defun guix-package-info-insert-hidden-text ()
  603. "Insert a message that current package is hidden."
  604. (insert "This package is ")
  605. (bui-format-insert "hidden" 'guix-package-info-hidden)
  606. (insert ", so do not tell anyone about it ;-)\n"))
  607. (defun guix-package-info-insert-output (output entry)
  608. "Insert OUTPUT at point.
  609. Make some fancy text with buttons and additional stuff if the
  610. current OUTPUT is installed (if there is such output in
  611. `installed' parameter of a package ENTRY)."
  612. (let* ((installed (bui-entry-non-void-value entry 'installed))
  613. (obsolete (eq (bui-entry-non-void-value entry 'known-status)
  614. 'obsolete))
  615. (installed-entry (--find
  616. (string= (bui-entry-non-void-value it 'output)
  617. output)
  618. installed))
  619. (action-type (if installed-entry 'delete 'install))
  620. (profile (guix-ui-current-profile)))
  621. (bui-insert-indent)
  622. (bui-format-insert output
  623. (if installed-entry
  624. 'guix-package-info-installed-outputs
  625. 'guix-package-info-uninstalled-outputs)
  626. guix-package-info-output-format)
  627. ;; Do not allow a user to install/delete anything to/from a system
  628. ;; profile or "guix pull"-ed profile, so add action buttons only for
  629. ;; usual profiles.
  630. (when (and profile
  631. (not (guix-system-profile? profile))
  632. (not (guix-pulled-profile? profile)))
  633. (guix-package-info-insert-action-button action-type entry output)
  634. (when obsolete
  635. (bui-insert-indent)
  636. (guix-package-info-insert-action-button 'upgrade entry output)))
  637. (bui-newline)
  638. (when installed-entry
  639. (bui-info-insert-entry installed-entry 'guix-installed-output 2))))
  640. (defun guix-package-info-insert-action-button (type entry output)
  641. "Insert button to process an action on a package OUTPUT at point.
  642. TYPE is one of the following symbols: `install', `delete', `upgrade'.
  643. ENTRY is an alist with package info."
  644. (let ((type-str (capitalize (symbol-name type)))
  645. (full-name (guix-package-entry->name-specification entry output)))
  646. (bui-insert-action-button
  647. type-str
  648. (lambda (btn)
  649. (guix-process-package-actions
  650. (guix-ui-current-profile)
  651. `((,(button-get btn 'action-type) (,(button-get btn 'id)
  652. ,(button-get btn 'output))))
  653. (current-buffer)))
  654. (concat type-str " '" full-name "'")
  655. 'action-type type
  656. 'id (or (bui-entry-non-void-value entry 'package-id)
  657. (bui-entry-id entry))
  658. 'output output)))
  659. (defun guix-package-info-show-store-path (entry-id package-id)
  660. "Show store directories of the package outputs in the current buffer.
  661. ENTRY-ID is an ID of the current entry (package or output).
  662. PACKAGE-ID is an ID of the package which store path to show."
  663. (let* ((entries (bui-current-entries))
  664. (entry (bui-entry-by-id entries entry-id))
  665. (dirs (guix-package-store-path package-id)))
  666. (or dirs
  667. (error "Couldn't define store directory of the package"))
  668. (let* ((new-entry (cons (cons 'store-path dirs)
  669. entry))
  670. (new-entries (bui-replace-entry entries entry-id new-entry)))
  671. (setf (bui-item-entries bui-item)
  672. new-entries)
  673. (bui-redisplay-goto-button)
  674. (let ((dir (car dirs)))
  675. (if (file-exists-p dir)
  676. (if guix-package-info-auto-find-package
  677. (find-file dir)
  678. (message nil))
  679. (message "'%s' does not exist.\nTry to build this package."
  680. dir))))))
  681. (defun guix-package-info-insert-misc (entry)
  682. "Insert various buttons and other info for package ENTRY at point."
  683. (when (eq (bui-entry-non-void-value entry 'known-status)
  684. 'known)
  685. (let* ((entry-id (bui-entry-id entry))
  686. (package-id (or (bui-entry-non-void-value entry 'package-id)
  687. entry-id))
  688. (full-name (guix-package-entry->name-specification entry))
  689. (store-path (bui-entry-non-void-value entry 'store-path)))
  690. (bui-info-insert-title-simple "Package")
  691. (if store-path
  692. (bui-info-insert-value-indent store-path 'bui-file)
  693. (bui-insert-action-button
  694. "Show"
  695. (lambda (btn)
  696. (guix-package-info-show-store-path
  697. (button-get btn 'entry-id)
  698. (button-get btn 'package-id)))
  699. "Show the store directory of the current package"
  700. 'entry-id entry-id
  701. 'package-id package-id))
  702. (when guix-package-info-button-functions
  703. (bui-newline)
  704. (bui-mapinsert (lambda (fun)
  705. (funcall fun package-id full-name))
  706. guix-package-info-button-functions
  707. (bui-get-indent)
  708. :indent bui-indent
  709. :column (bui-fill-column)))
  710. (bui-newline))))
  711. (defun guix-package-info-insert-build-button (id full-name)
  712. "Insert button to build a package defined by ID."
  713. (bui-insert-action-button
  714. "Build"
  715. (lambda (btn)
  716. (guix-build-package (button-get btn 'id)
  717. (format "Build '%s' package?" full-name)))
  718. "Build the current package"
  719. 'id id))
  720. (defun guix-package-info-insert-build-log-button (id _name)
  721. "Insert button to show build log of a package defined by ID."
  722. (bui-insert-action-button
  723. "Build Log"
  724. (lambda (btn)
  725. (guix-package-find-build-log (button-get btn 'id)))
  726. "View build log of the current package"
  727. 'id id))
  728. (declare-function guix-package-graph "guix-graph" t)
  729. (defun guix-package-info-insert-graph-button (id _name)
  730. "Insert button to show a graph of a package defined by ID."
  731. (bui-insert-action-button
  732. "Graph"
  733. (lambda (btn)
  734. (guix-package-graph (button-get btn 'id)
  735. (guix-read-graph-backend)
  736. (guix-read-graph-node-type)))
  737. "View graph of the current package"
  738. 'id id))
  739. (defun guix-package-info-insert-size-button (_id name)
  740. "Insert button to show a size of a package NAME."
  741. (bui-insert-action-button
  742. "Size"
  743. (lambda (btn)
  744. (guix-package-size (button-get btn 'name)
  745. (guix-read-package-size-type)))
  746. (format "View size of '%s' package" name)
  747. 'name name))
  748. (defun guix-package-info-insert-lint-button (id _name)
  749. "Insert button to lint a package defined by ID."
  750. (bui-insert-action-button
  751. "Lint"
  752. (lambda (btn)
  753. (guix-package-lint (list (button-get btn 'id))
  754. (and current-prefix-arg
  755. (guix-read-lint-checker-names))))
  756. "Lint the current package"
  757. 'id id))
  758. (defun guix-package-info-show-source (entry-id package-id)
  759. "Show file name of a package source in the current info buffer.
  760. Find the file if needed (see `guix-package-info-auto-find-source').
  761. ENTRY-ID is an ID of the current entry (package or output).
  762. PACKAGE-ID is an ID of the package which source to show."
  763. (let* ((entries (bui-current-entries))
  764. (entry (bui-entry-by-id entries entry-id))
  765. (file (guix-package-source-file-name package-id)))
  766. (or file
  767. (error "Couldn't define file name of the package source"))
  768. (let* ((new-entry (cons (cons 'source-file file)
  769. entry))
  770. (new-entries (bui-replace-entry entries entry-id new-entry)))
  771. (setf (bui-item-entries bui-item)
  772. new-entries)
  773. (bui-redisplay-goto-button)
  774. (if (file-exists-p file)
  775. (if guix-package-info-auto-find-source
  776. (guix-find-file file)
  777. (message "The file name of the package source is displayed."))
  778. (if guix-package-info-auto-download-source
  779. (guix-package-info-download-source package-id)
  780. (message "The source does not exist in the store."))))))
  781. (defun guix-package-info-download-source (package-id)
  782. "Download a source of the package PACKAGE-ID."
  783. (setq guix-package-info-download-buffer (current-buffer))
  784. (guix-package-source-build-derivation
  785. package-id
  786. "The source does not exist in the store. Download it?"))
  787. (defun guix-package-info-insert-source (source entry)
  788. "Insert SOURCE from package ENTRY at point.
  789. SOURCE is a list of URLs."
  790. (bui-insert-non-nil source
  791. (let* ((source-file (bui-entry-non-void-value entry 'source-file))
  792. (entry-id (bui-entry-id entry))
  793. (package-id (or (bui-entry-non-void-value entry 'package-id)
  794. entry-id)))
  795. (if (null source-file)
  796. (bui-insert-action-button
  797. "Show"
  798. (lambda (btn)
  799. (guix-package-info-show-source (button-get btn 'entry-id)
  800. (button-get btn 'package-id)))
  801. "Show the source store directory of the current package"
  802. 'entry-id entry-id
  803. 'package-id package-id)
  804. (unless (file-exists-p source-file)
  805. (bui-insert-action-button
  806. "Download"
  807. (lambda (btn)
  808. (guix-package-info-download-source
  809. (button-get btn 'package-id)))
  810. "Download the source into the store"
  811. 'package-id package-id))
  812. (bui-info-insert-value-indent source-file 'bui-file))
  813. (bui-info-insert-value-indent source 'guix-package-source))))
  814. (defun guix-package-info-redisplay-after-download ()
  815. "Redisplay an 'info' buffer after downloading the package source.
  816. This function is used to hide a \"Download\" button if needed."
  817. (when (buffer-live-p guix-package-info-download-buffer)
  818. (with-current-buffer guix-package-info-download-buffer
  819. (bui-redisplay-goto-button))
  820. (setq guix-package-info-download-buffer nil)))
  821. (add-hook 'guix-after-source-download-hook
  822. 'guix-package-info-redisplay-after-download)
  823. (defun guix-package-entry-ensure-known (entry)
  824. "Signal an error if package ENTRY is unknown."
  825. (unless (eq (bui-entry-non-void-value entry 'known-status)
  826. 'known)
  827. (error "This command is not available for obsolete or unknown packages")))
  828. (defun guix-package-info-edit (entry &optional directory)
  829. "Go to the location of the package ENTRY.
  830. See `guix-find-location' for the meaning of DIRECTORY."
  831. (interactive
  832. (let ((entry (guix-read-package-entry-by-name)))
  833. (guix-package-entry-ensure-known entry)
  834. (list entry
  835. (guix-read-directory))))
  836. (guix-find-location (bui-entry-non-void-value entry 'location)
  837. directory))
  838. (defun guix-package-info-graph (entry backend node-type)
  839. "Show BACKEND/NODE-TYPE graph for the package ENTRY."
  840. (interactive
  841. (list (guix-read-package-entry-by-name)
  842. (guix-read-graph-backend)
  843. (guix-read-graph-node-type)))
  844. (guix-package-graph (if (eq (bui-entry-non-void-value entry 'known-status)
  845. 'known)
  846. (bui-entry-id entry)
  847. (bui-entry-non-void-value entry 'name))
  848. backend node-type))
  849. (defun guix-package-info-size (entry &optional type)
  850. "Show size of the package ENTRY.
  851. See `guix-package-size' for the meaning of TYPE."
  852. (interactive
  853. (list (guix-read-package-entry-by-name)
  854. (guix-read-package-size-type)))
  855. (guix-package-size (if (eq (bui-entry-non-void-value entry 'known-status)
  856. 'known)
  857. (guix-package-entry->name-specification entry)
  858. ;; Take file name of the first output.
  859. ;; FIXME It is better to ask for an output, if
  860. ;; there are several outputs.
  861. (bui-entry-value
  862. (car (bui-entry-value entry 'installed))
  863. 'file-name))
  864. type))
  865. (defun guix-package-info-lint (entry &optional checkers)
  866. "Lint the package ENTRY.
  867. Interactively with prefix, prompt for CHECKERS.
  868. See `guix-package-lint' for details."
  869. (interactive
  870. (let ((entry (guix-read-package-entry-by-name)))
  871. (guix-package-entry-ensure-known entry)
  872. (list entry
  873. (and current-prefix-arg
  874. (guix-read-lint-checker-names)))))
  875. (guix-package-lint (list (bui-entry-id entry)) checkers))
  876. (defun guix-package-info-install (entry output)
  877. "Install package OUTPUT to the current profile.
  878. Interactively, prompt for package ENTRY and OUTPUT (if there are
  879. more than one)."
  880. (interactive (guix-read-package-entry-and-output))
  881. (if (member output (guix-package-entry-installed-outputs entry))
  882. (user-error "'%s' is already installed"
  883. (guix-package-entry->name-specification entry output))
  884. (guix-process-package-actions
  885. (guix-ui-current-profile)
  886. `((install (,(bui-entry-id entry) ,output)))
  887. (current-buffer))))
  888. (defun guix-package-info-delete (entry output)
  889. "Delete package OUTPUT from the current profile.
  890. Interactively, prompt for package ENTRY and OUTPUT (if there are
  891. more than one)."
  892. (interactive (guix-read-package-entry-and-output))
  893. (if (member output (guix-package-entry-installed-outputs entry))
  894. (guix-process-package-actions
  895. (guix-ui-current-profile)
  896. `((delete (,(bui-entry-id entry) ,output)))
  897. (current-buffer))
  898. (user-error "'%s' cannot be deleted as it is not installed"
  899. (guix-package-entry->name-specification entry output))))
  900. (defun guix-package-info-upgrade (entry output)
  901. "Upgrade package OUTPUT in the current profile.
  902. Interactively, prompt for package ENTRY and OUTPUT (if there are
  903. more than one)."
  904. (interactive (guix-read-package-entry-and-output))
  905. (if (member output (guix-package-entry-installed-outputs entry))
  906. (when (or (eq (bui-entry-non-void-value entry 'known-status)
  907. 'obsolete)
  908. (y-or-n-p
  909. (format "'%s' is not obsolete. Try to upgrade it anyway? "
  910. (guix-package-entry->name-specification
  911. entry output))))
  912. (guix-process-package-actions
  913. (guix-ui-current-profile)
  914. `((upgrade (,(bui-entry-id entry) ,output)))
  915. (current-buffer)))
  916. (when (y-or-n-p
  917. (format "'%s' is not installed. Install it? "
  918. (guix-package-entry->name-specification entry output)))
  919. (guix-process-package-actions
  920. (guix-ui-current-profile)
  921. `((install (,(bui-entry-id entry) ,output)))
  922. (current-buffer)))))
  923. ;;; Package 'list'
  924. (guix-ui-define-interface package list
  925. :mode-name "Package-List"
  926. :buffer-name "*Guix Packages*"
  927. :get-entries-function 'guix-package-list-get-entries
  928. :describe-function 'guix-ui-list-describe
  929. :format '((name guix-package-list-get-name 20 t)
  930. (version nil 10 nil)
  931. (outputs nil 13 t)
  932. (installed guix-package-list-get-installed-outputs 13 t)
  933. (synopsis bui-list-get-one-line 30 nil))
  934. :required '(id known-status superseded hidden)
  935. :hint 'guix-package-list-hint
  936. :sort-key '(name)
  937. :marks '((install . ?I)
  938. (upgrade . ?U)
  939. (delete . ?D)))
  940. (let ((map guix-package-list-mode-map))
  941. (define-key map (kbd "B") 'guix-package-list-latest-builds)
  942. (define-key map (kbd "G") 'guix-package-list-graph)
  943. (define-key map (kbd "z") 'guix-package-list-size)
  944. (define-key map (kbd "L") 'guix-package-list-lint)
  945. (define-key map (kbd "e") 'guix-package-list-edit)
  946. (define-key map (kbd "x") 'guix-package-list-execute)
  947. (define-key map (kbd "i") 'guix-package-list-mark-install)
  948. (define-key map (kbd "d") 'guix-package-list-mark-delete)
  949. (define-key map (kbd "U") 'guix-package-list-mark-upgrade)
  950. (define-key map (kbd "^") 'guix-package-list-mark-upgrades))
  951. (defface guix-package-list-installed
  952. '((t :inherit guix-package-info-installed-outputs))
  953. "Face used for installed packages."
  954. :group 'guix-package-list-faces)
  955. (defface guix-package-list-unknown
  956. '((t :inherit guix-package-info-unknown))
  957. "Face used for unknown packages.
  958. See `guix-package-info-unknown' face for details."
  959. :group 'guix-package-list-faces)
  960. (defface guix-package-list-obsolete
  961. '((t :inherit guix-package-info-obsolete))
  962. "Face used for obsolete packages.
  963. See `guix-package-info-obsolete' face for details."
  964. :group 'guix-package-list-faces)
  965. (defface guix-package-list-future
  966. '((t :inherit guix-package-info-future))
  967. "Face used for packages from the future.
  968. See `guix-package-info-future' face for details."
  969. :group 'guix-package-list-faces)
  970. (defface guix-package-list-superseded
  971. '((t :inherit guix-package-info-superseded))
  972. "Face used for superseded packages.
  973. See `guix-package-info-superseded' face for details."
  974. :group 'guix-package-list-faces)
  975. (defface guix-package-list-hidden
  976. '((t :inherit guix-package-info-hidden))
  977. "Face used for hidden packages.
  978. See `guix-package-info-hidden' face for details."
  979. :group 'guix-package-list-faces)
  980. (defcustom guix-package-list-generation-marking-enabled nil
  981. "If non-nil, allow putting marks in a list with 'generation packages'.
  982. By default this is disabled, because it may be confusing. For
  983. example, a package is installed in some generation, so a user can
  984. mark it for deletion in the list of packages from this
  985. generation, but the package may not be installed in the latest
  986. generation, so actually it cannot be deleted.
  987. If you managed to understand the explanation above or if you
  988. really know what you do or if you just don't care, you can set
  989. this variable to t. It should not do much harm anyway (most
  990. likely)."
  991. :type 'boolean
  992. :group 'guix-package-list)
  993. (defvar guix-package-list-default-hint
  994. '(("\\[guix-package-list-edit]") " edit (go to) the package definition;\n"
  995. ("\\[guix-package-list-graph]") " view package graph; "
  996. ("\\[guix-package-list-size]") " view package size; "
  997. ("\\[guix-package-list-lint]") " lint;\n"
  998. ("\\[guix-package-list-mark-install]") " mark for installation; "
  999. ("\\[guix-package-list-mark-delete]") " mark for deletion;\n"
  1000. ("\\[guix-package-list-mark-upgrade]") " mark for upgrading; "
  1001. ("\\[guix-package-list-mark-upgrades]") " mark all for upgrading;\n"
  1002. ("\\[guix-package-list-execute]") " execute operation;\n"))
  1003. (defun guix-package-list-hint ()
  1004. (bui-format-hints
  1005. guix-package-list-default-hint
  1006. guix-ui-hint
  1007. (bui-default-hint)))
  1008. (defun guix-package-list-get-entries (profile search-type
  1009. &rest search-values)
  1010. "Return 'package' entries for displaying them in 'list' buffer."
  1011. (guix-eval-read
  1012. (guix-make-guile-expression
  1013. 'package/output-sexps
  1014. profile 'package search-type search-values
  1015. (cl-union guix-package-list-required-params
  1016. (bui-list-displayed-params 'guix-package)))))
  1017. (defun guix-package-list-get-name (name entry)
  1018. "Return NAME of the package ENTRY.
  1019. Colorize it with an appropriate face if needed."
  1020. (bui-get-string
  1021. name
  1022. (if (bui-entry-non-void-value entry 'hidden)
  1023. 'guix-package-list-hidden
  1024. (cl-case (bui-entry-non-void-value entry 'known-status)
  1025. ((known nil)
  1026. (cond
  1027. ((bui-entry-non-void-value entry 'superseded)
  1028. 'guix-package-list-superseded)
  1029. ((bui-entry-non-void-value entry 'installed)
  1030. 'guix-package-list-installed)))
  1031. (obsolete 'guix-package-list-obsolete)
  1032. (unknown 'guix-package-list-unknown)
  1033. (future 'guix-package-list-future)))))
  1034. (defun guix-package-list-get-installed-outputs (installed &optional _)
  1035. "Return string with outputs from INSTALLED entries."
  1036. (bui-get-string
  1037. (--map (bui-entry-non-void-value it 'output)
  1038. installed)))
  1039. (defun guix-package-list-marking-check ()
  1040. "Signal an error if marking is disabled for the current buffer."
  1041. (when (and (not guix-package-list-generation-marking-enabled)
  1042. (or (derived-mode-p 'guix-package-list-mode)
  1043. (derived-mode-p 'guix-output-list-mode))
  1044. (eq (guix-ui-current-search-type) 'generation))
  1045. (error "Action marks are disabled for lists of 'generation packages'")))
  1046. (defun guix-package-list-mark-outputs (mark default
  1047. &optional prompt available)
  1048. "Mark the current package with MARK and move to the next line.
  1049. If PROMPT is non-nil, use it to ask a user for outputs from
  1050. AVAILABLE list, otherwise mark all DEFAULT outputs."
  1051. (let ((outputs (if prompt
  1052. (guix-completing-read-multiple
  1053. prompt available nil t)
  1054. default)))
  1055. (apply #'bui-list--mark mark t outputs)))
  1056. (defun guix-package-list-mark-install (&optional arg)
  1057. "Mark the current package for installation and move to the next line.
  1058. With ARG, prompt for the outputs to install (several outputs may
  1059. be separated with \",\")."
  1060. (interactive "P")
  1061. (guix-package-list-marking-check)
  1062. (let* ((entry (bui-list-current-entry))
  1063. (all (bui-entry-non-void-value entry 'outputs))
  1064. (installed (guix-package-entry-installed-outputs entry))
  1065. (available (cl-set-difference all installed :test #'string=)))
  1066. (or available
  1067. (user-error "This package is already installed"))
  1068. (guix-package-list-mark-outputs
  1069. 'install '("out")
  1070. (and arg "Output(s) to install: ")
  1071. available)))
  1072. (defun guix-package-list-mark-delete (&optional arg)
  1073. "Mark the current package for deletion and move to the next line.
  1074. With ARG, prompt for the outputs to delete (several outputs may
  1075. be separated with \",\")."
  1076. (interactive "P")
  1077. (guix-package-list-marking-check)
  1078. (let* ((entry (bui-list-current-entry))
  1079. (installed (guix-package-entry-installed-outputs entry)))
  1080. (or installed
  1081. (user-error "This package is not installed"))
  1082. (guix-package-list-mark-outputs
  1083. 'delete installed
  1084. (and arg "Output(s) to delete: ")
  1085. installed)))
  1086. (defun guix-package-list-mark-upgrade (&optional arg)
  1087. "Mark the current package for upgrading and move to the next line.
  1088. With ARG, prompt for the outputs to upgrade (several outputs may
  1089. be separated with \",\")."
  1090. (interactive "P")
  1091. (guix-package-list-marking-check)
  1092. (let* ((entry (bui-list-current-entry))
  1093. (installed (guix-package-entry-installed-outputs entry)))
  1094. (or installed
  1095. (user-error "This package is not installed"))
  1096. (when (or (eq (bui-entry-non-void-value entry 'known-status)
  1097. 'obsolete)
  1098. (y-or-n-p "This package is not obsolete. Try to upgrade it anyway? "))
  1099. (guix-package-list-mark-outputs
  1100. 'upgrade installed
  1101. (and arg "Output(s) to upgrade: ")
  1102. installed))))
  1103. (defun guix-package-mark-upgrades (fun &optional all)
  1104. "Mark all obsolete packages for upgrading.
  1105. Use FUN to perform marking of the current line. FUN should
  1106. take an entry as argument.
  1107. If ALL is non-nil, mark all installed (not only obsolete) packages."
  1108. (guix-package-list-marking-check)
  1109. (let ((entries (--filter (if all
  1110. (bui-entry-non-void-value it 'installed)
  1111. (eq (bui-entry-non-void-value it 'known-status)
  1112. 'obsolete))
  1113. (bui-current-entries))))
  1114. (bui-list-for-each-line
  1115. (lambda ()
  1116. (let* ((id (bui-list-current-id))
  1117. (entry (--find (equal id (bui-entry-id it))
  1118. entries)))
  1119. (when entry
  1120. (funcall fun entry)))))))
  1121. (defun guix-package-list-mark-upgrades (&optional arg)
  1122. "Mark all obsolete packages for upgrading.
  1123. With ARG, mark all installed (including non-obsolete) packages."
  1124. (interactive "P")
  1125. (guix-package-mark-upgrades
  1126. (lambda (entry)
  1127. (apply #'bui-list--mark
  1128. 'upgrade nil
  1129. (guix-package-entry-installed-outputs entry)))
  1130. arg))
  1131. (defun guix-package-assert-non-system-profile ()
  1132. "Verify that the current profile is not a system one.
  1133. The current profile is the one used by the current buffer."
  1134. (--when-let (guix-ui-current-profile)
  1135. (guix-assert-non-system-profile it)))
  1136. (defun guix-package-execute-actions (fun)
  1137. "Perform actions on the marked packages.
  1138. Use FUN to define actions suitable for `guix-process-package-actions'.
  1139. FUN should take action-type as argument."
  1140. (guix-package-assert-non-system-profile)
  1141. (let ((actions (-non-nil (mapcar fun '(install delete upgrade)))))
  1142. (if actions
  1143. (guix-process-package-actions (guix-ui-current-profile)
  1144. actions (current-buffer))
  1145. (user-error "No operations specified"))))
  1146. (defun guix-package-list-execute ()
  1147. "Perform actions on the marked packages."
  1148. (interactive)
  1149. (guix-package-execute-actions #'guix-package-list-make-action))
  1150. (defun guix-package-list-make-action (action-type)
  1151. "Return action specification for the packages marked with ACTION-TYPE.
  1152. Return nil, if there are no packages marked with ACTION-TYPE.
  1153. The specification is suitable for `guix-process-package-actions'."
  1154. (let ((specs (bui-list-get-marked-args action-type)))
  1155. (and specs (cons action-type specs))))
  1156. (defun guix-package-list-edit (&optional directory)
  1157. "Go to the location of the current package.
  1158. See `guix-find-location' for the meaning of DIRECTORY."
  1159. (interactive (list (guix-read-directory)))
  1160. (guix-find-package-definition (bui-list-current-id) directory))
  1161. (defun guix-package-list-graph (backend node-type)
  1162. "Show BACKEND/NODE-TYPE graph for the current package."
  1163. (interactive
  1164. (list (guix-read-graph-backend)
  1165. (guix-read-graph-node-type)))
  1166. (let ((entry (bui-list-current-entry)))
  1167. (guix-package-graph (if (eq (bui-entry-non-void-value entry 'known-status)
  1168. 'known)
  1169. (bui-list-current-id)
  1170. (bui-entry-non-void-value entry 'name))
  1171. backend node-type)))
  1172. (defun guix-package-list-size (&optional type)
  1173. "Show size of the current package.
  1174. See `guix-package-size' for the meaning of TYPE."
  1175. (interactive (list (guix-read-package-size-type)))
  1176. (guix-package-size (guix-package-entry->name-specification
  1177. (bui-list-current-entry))
  1178. type))
  1179. (defun guix-package-list-lint (&optional checkers)
  1180. "Lint marked (or the current) packages.
  1181. Interactively with prefix, prompt for CHECKERS.
  1182. See `guix-package-lint' for details."
  1183. (interactive
  1184. (list (and current-prefix-arg
  1185. (guix-read-lint-checker-names))))
  1186. (guix-package-lint (bui-list-marked-or-current) checkers))
  1187. (declare-function build-farm-build-latest-prompt-args "build-farm-build" t)
  1188. (declare-function build-farm-latest-builds "build-farm-build" t)
  1189. (declare-function build-farm-job-name-specification "build-farm" t)
  1190. (defun guix-package-list-latest-builds (number &rest args)
  1191. "Display latest NUMBER of `build-farm' builds of the current package.
  1192. Interactively, with prefix argument, prompt for NUMBER and ARGS."
  1193. (interactive
  1194. (let ((entry (bui-list-current-entry)))
  1195. (guix-assert-build-farm)
  1196. (require 'build-farm-build)
  1197. (build-farm-build-latest-prompt-args
  1198. :job (build-farm-job-name-specification
  1199. (bui-entry-non-void-value entry 'name)
  1200. (bui-entry-non-void-value entry 'version)))))
  1201. (guix-assert-build-farm)
  1202. (apply #'build-farm-latest-builds number args))
  1203. ;;; Output 'list'
  1204. (guix-ui-define-interface output list
  1205. :mode-name "Output-List"
  1206. :buffer-name "*Guix Packages*"
  1207. :get-entries-function 'guix-output-list-get-entries
  1208. :describe-function 'guix-output-list-describe
  1209. :format '((name guix-package-list-get-name 20 t)
  1210. (version nil 10 nil)
  1211. (output nil 9 t)
  1212. (installed nil 12 t)
  1213. (synopsis bui-list-get-one-line 30 nil))
  1214. :required '(id package-id known-status superseded hidden)
  1215. :hint 'guix-output-list-hint
  1216. :sort-key '(name)
  1217. :marks '((install . ?I)
  1218. (upgrade . ?U)
  1219. (delete . ?D)))
  1220. (let ((map guix-output-list-mode-map))
  1221. (define-key map (kbd "B") 'guix-package-list-latest-builds)
  1222. (define-key map (kbd "G") 'guix-output-list-graph)
  1223. (define-key map (kbd "z") 'guix-package-list-size)
  1224. (define-key map (kbd "L") 'guix-output-list-lint)
  1225. (define-key map (kbd "e") 'guix-output-list-edit)
  1226. (define-key map (kbd "x") 'guix-output-list-execute)
  1227. (define-key map (kbd "i") 'guix-output-list-mark-install)
  1228. (define-key map (kbd "d") 'guix-output-list-mark-delete)
  1229. (define-key map (kbd "U") 'guix-output-list-mark-upgrade)
  1230. (define-key map (kbd "^") 'guix-output-list-mark-upgrades))
  1231. (defvar guix-output-list-default-hint
  1232. '(("\\[guix-output-list-edit]") " edit (go to) the package definition;\n"
  1233. ("\\[guix-output-list-graph]") " view package graph; "
  1234. ("\\[guix-package-list-size]") " view package size; "
  1235. ("\\[guix-output-list-lint]") " lint;\n"
  1236. ("\\[guix-output-list-mark-install]") " mark for installation; "
  1237. ("\\[guix-output-list-mark-delete]") " mark for deletion;\n"
  1238. ("\\[guix-output-list-mark-upgrade]") " mark for upgrading; "
  1239. ("\\[guix-output-list-mark-upgrades]") " mark all for upgrading;\n"
  1240. ("\\[guix-output-list-execute]") " execute operation;\n"))
  1241. (defun guix-output-list-hint ()
  1242. (bui-format-hints
  1243. guix-output-list-default-hint
  1244. guix-ui-hint
  1245. (bui-default-hint)))
  1246. (defun guix-output-list-get-entries (profile search-type
  1247. &rest search-values)
  1248. "Return 'output' entries for displaying them in 'list' buffer."
  1249. (guix-eval-read
  1250. (guix-make-guile-expression
  1251. 'package/output-sexps
  1252. profile 'output search-type search-values
  1253. (cl-union guix-output-list-required-params
  1254. (bui-list-displayed-params 'guix-output)))))
  1255. (defun guix-output-list-mark-install ()
  1256. "Mark the current output for installation and move to the next line."
  1257. (interactive)
  1258. (guix-package-list-marking-check)
  1259. (let* ((entry (bui-list-current-entry))
  1260. (installed (bui-entry-non-void-value entry 'installed)))
  1261. (if installed
  1262. (user-error "This output is already installed")
  1263. (bui-list--mark 'install t))))
  1264. (defun guix-output-list-mark-delete ()
  1265. "Mark the current output for deletion and move to the next line."
  1266. (interactive)
  1267. (guix-package-list-marking-check)
  1268. (let* ((entry (bui-list-current-entry))
  1269. (installed (bui-entry-non-void-value entry 'installed)))
  1270. (if installed
  1271. (bui-list--mark 'delete t)
  1272. (user-error "This output is not installed"))))
  1273. (defun guix-output-list-mark-upgrade ()
  1274. "Mark the current output for upgrading and move to the next line."
  1275. (interactive)
  1276. (guix-package-list-marking-check)
  1277. (let* ((entry (bui-list-current-entry))
  1278. (installed (bui-entry-non-void-value entry 'installed)))
  1279. (or installed
  1280. (user-error "This output is not installed"))
  1281. (when (or (eq (bui-entry-non-void-value entry 'known-status)
  1282. 'obsolete)
  1283. (y-or-n-p "This output is not obsolete. Try to upgrade it anyway? "))
  1284. (bui-list--mark 'upgrade t))))
  1285. (defun guix-output-list-mark-upgrades (&optional arg)
  1286. "Mark all obsolete package outputs for upgrading.
  1287. With ARG, mark all installed (including non-obsolete) packages."
  1288. (interactive "P")
  1289. (guix-package-mark-upgrades
  1290. (lambda (_) (bui-list--mark 'upgrade))
  1291. arg))
  1292. (defun guix-output-list-execute ()
  1293. "Perform actions on the marked outputs."
  1294. (interactive)
  1295. (guix-package-execute-actions #'guix-output-list-make-action))
  1296. (defun guix-output-list-make-action (action-type)
  1297. "Return action specification for the outputs marked with ACTION-TYPE.
  1298. Return nil, if there are no outputs marked with ACTION-TYPE.
  1299. The specification is suitable for `guix-process-output-actions'."
  1300. (let ((ids (bui-list-get-marked-id-list action-type)))
  1301. (and ids (cons action-type
  1302. (mapcar #'guix-package-id-and-output-by-output-id
  1303. ids)))))
  1304. (defun guix-output-list-describe (&rest ids)
  1305. "Describe outputs with IDS (list of output identifiers)."
  1306. (let ((pids (--map (car (guix-package-id-and-output-by-output-id it))
  1307. ids)))
  1308. (bui-get-display-entries
  1309. 'guix-package 'info
  1310. (cl-list* (guix-ui-current-profile)
  1311. 'id (cl-remove-duplicates pids))
  1312. 'add)))
  1313. (defun guix-output-list-edit (&optional directory)
  1314. "Go to the location of the current package.
  1315. See `guix-find-location' for the meaning of DIRECTORY."
  1316. (interactive (list (guix-read-directory)))
  1317. (guix-find-package-definition
  1318. (bui-entry-non-void-value (bui-list-current-entry)
  1319. 'package-id)
  1320. directory))
  1321. (defun guix-output-list-graph (backend node-type)
  1322. "Show BACKEND/NODE-TYPE graph for the current package."
  1323. (interactive
  1324. (list (guix-read-graph-backend)
  1325. (guix-read-graph-node-type)))
  1326. (let ((entry (bui-list-current-entry)))
  1327. (guix-package-graph (if (eq (bui-entry-non-void-value entry 'known-status)
  1328. 'known)
  1329. (bui-entry-non-void-value entry 'package-id)
  1330. (bui-entry-non-void-value entry 'name))
  1331. backend node-type)))
  1332. (defun guix-output-list-lint (&optional checkers)
  1333. "Lint the current package.
  1334. Interactively with prefix, prompt for CHECKERS.
  1335. See `guix-package-lint' for details."
  1336. (interactive
  1337. (list (and current-prefix-arg
  1338. (guix-read-lint-checker-names))))
  1339. (guix-package-lint
  1340. (list (bui-entry-non-void-value (bui-list-current-entry)
  1341. 'package-id))
  1342. checkers))
  1343. ;;; Interactive commands
  1344. (defvar guix-package-search-params '(name synopsis description)
  1345. "Default list of package parameters for searching by regexp.")
  1346. (defvar guix-package-search-history nil
  1347. "A history of minibuffer prompts.")
  1348. ;;;###autoload
  1349. (defun guix-packages-by-name (name &optional profile)
  1350. "Display Guix packages with NAME.
  1351. NAME is a string with name specification. It may optionally contain
  1352. a version number. Examples: \"guile\", \"guile@2.0.11\".
  1353. If PROFILE is nil, use `guix-current-profile'.
  1354. Interactively with prefix, prompt for PROFILE."
  1355. (interactive
  1356. (let (default-pkg)
  1357. (when guix-package-use-name-at-point
  1358. (let ((at-point (thing-at-point 'symbol t)))
  1359. (when (stringp at-point)
  1360. (let ((at-point (car (split-string at-point "@"))))
  1361. (setq default-pkg (and (member at-point (guix-package-names))
  1362. at-point))))))
  1363. (list (guix-read-package-name "Package: " default-pkg)
  1364. (guix-ui-read-package-profile))))
  1365. (guix-package-get-display profile 'name name))
  1366. ;;;###autoload
  1367. (defun guix-packages-by-regexp (regexp &optional params profile)
  1368. "Search for Guix packages by REGEXP.
  1369. PARAMS are package parameters that should be searched.
  1370. If PARAMS are not specified, use `guix-package-search-params'.
  1371. If PROFILE is nil, use `guix-current-profile'.
  1372. Interactively with prefix, prompt for PROFILE."
  1373. (interactive
  1374. (list (read-regexp "Regexp: " nil 'guix-package-search-history)
  1375. nil (guix-ui-read-package-profile)))
  1376. (guix-package-get-display profile 'regexp regexp
  1377. (or params guix-package-search-params)))
  1378. ;;;###autoload
  1379. (define-obsolete-function-alias 'guix-search-by-regexp
  1380. 'guix-packages-by-regexp "0.5.3")
  1381. ;;;###autoload
  1382. (defun guix-packages-by-name-regexp (regexp &optional profile)
  1383. "Search for Guix packages matching REGEXP in a package name.
  1384. If PROFILE is nil, use `guix-current-profile'.
  1385. Interactively with prefix, prompt for PROFILE."
  1386. (interactive
  1387. (list (read-string "Package name by regexp: "
  1388. nil 'guix-package-search-history)
  1389. (guix-ui-read-package-profile)))
  1390. (guix-packages-by-regexp regexp '(name) profile))
  1391. ;;;###autoload
  1392. (define-obsolete-function-alias 'guix-search-by-name
  1393. 'guix-packages-by-name-regexp "0.5.3")
  1394. ;;;###autoload
  1395. (defun guix-packages-by-license (license &optional profile)
  1396. "Display Guix packages with LICENSE.
  1397. LICENSE is a license name string.
  1398. If PROFILE is nil, use `guix-current-profile'.
  1399. Interactively with prefix, prompt for PROFILE."
  1400. (interactive
  1401. (list (guix-read-license-name)
  1402. (guix-ui-read-package-profile)))
  1403. (guix-package-get-display profile 'license license))
  1404. ;;;###autoload
  1405. (defun guix-packages-by-location (location &optional profile)
  1406. "Display Guix packages placed in LOCATION file.
  1407. If PROFILE is nil, use `guix-current-profile'.
  1408. Interactively with prefix, prompt for PROFILE."
  1409. (interactive
  1410. (list (guix-read-package-location-file)
  1411. (guix-ui-read-package-profile)))
  1412. (guix-package-get-display profile 'location location))
  1413. ;;;###autoload
  1414. (defun guix-package-from-file (file &optional profile)
  1415. "Display Guix package that the code from FILE evaluates to.
  1416. If PROFILE is nil, use `guix-current-profile'.
  1417. Interactively prompt for FILE (see also `guix-support-dired').
  1418. With prefix argument, prompt for PROFILE as well."
  1419. (interactive
  1420. (list (guix-read-file-name-maybe "File with package: ")
  1421. (guix-ui-read-package-profile)))
  1422. (bui-get-display-entries
  1423. 'guix-package 'info
  1424. (list (or profile guix-current-profile) 'from-file file)
  1425. 'add))
  1426. ;;;###autoload
  1427. (defun guix-packages-from-system-config-file (file &optional profile)
  1428. "Display Guix packages from the operating system configuration FILE.
  1429. Make sure FILE has a proper 'operating-system' declaration. You
  1430. may check it, for example, by running the following shell command:
  1431. guix system build --dry-run FILE
  1432. See also Info node `(guix) System Configuration'.
  1433. If PROFILE is nil, use system profile (it is used to show what
  1434. packages from FILE are installed in PROFILE).
  1435. Interactively, prompt for FILE (see also `guix-support-dired').
  1436. With prefix argument, prompt for PROFILE as well.
  1437. Note: This command displays only those packages that are placed
  1438. in 'packages' field of the 'operating-system' declaration. An
  1439. installed system also contains packages installed by
  1440. services (like 'guix' or 'shepherd'). To see all the packages
  1441. installed in a system profile, use
  1442. '\\[guix-installed-system-packages]' command."
  1443. (interactive
  1444. (list (guix-read-os-file-name)
  1445. (and current-prefix-arg
  1446. (guix-read-package-profile guix-system-profile))))
  1447. (guix-package-get-display (or profile guix-system-profile)
  1448. 'from-os-file file))
  1449. ;;;###autoload
  1450. (defun guix-installed-packages (&optional profile)
  1451. "Display information about installed Guix packages.
  1452. If PROFILE is nil, use `guix-current-profile'.
  1453. Interactively with prefix, prompt for PROFILE."
  1454. (interactive (list (guix-ui-read-package-profile)))
  1455. (guix-package-get-display profile 'installed))
  1456. ;;;###autoload
  1457. (defun guix-installed-user-packages ()
  1458. "Display information about Guix packages installed in a user profile."
  1459. (interactive)
  1460. (guix-installed-packages guix-user-profile))
  1461. ;;;###autoload
  1462. (defun guix-installed-system-packages ()
  1463. "Display information about Guix packages installed in a system profile."
  1464. (interactive)
  1465. (guix-installed-packages guix-system-profile))
  1466. ;;;###autoload
  1467. (defun guix-obsolete-packages (&optional profile)
  1468. "Display information about obsolete (or unknown) Guix packages.
  1469. If PROFILE is nil, use `guix-current-profile'.
  1470. Interactively with prefix, prompt for PROFILE."
  1471. (interactive (list (guix-ui-read-package-profile)))
  1472. (guix-package-get-display profile 'unknown))
  1473. ;;;###autoload
  1474. (defun guix-superseded-packages (&optional profile)
  1475. "Display information about superseded Guix packages.
  1476. If PROFILE is nil, use `guix-current-profile'.
  1477. Interactively with prefix, prompt for PROFILE."
  1478. (interactive (list (guix-ui-read-package-profile)))
  1479. (guix-package-get-display profile 'superseded))
  1480. (defun guix-read-package-dependent-type ()
  1481. "Prompt a user for a type of dependent packages."
  1482. (intern
  1483. (completing-read "Dependency type (\"all\" or \"direct\"): "
  1484. '("all" "direct")
  1485. nil t nil nil "all")))
  1486. ;;;###autoload
  1487. (defun guix-dependent-packages (packages &optional type profile)
  1488. "Display Guix packages that depend on PACKAGES.
  1489. This is similar to 'guix refresh --list-dependent PACKAGES ...'.
  1490. See Info node `(guix) Invoking guix refresh' for details.
  1491. TYPE should be a symbol `all' or `direct'. Interactively, prompt
  1492. for it.
  1493. If PROFILE is nil, use `guix-current-profile'.
  1494. Interactively with prefix, prompt for PROFILE."
  1495. (interactive
  1496. (list (guix-read-package-names)
  1497. (guix-read-package-dependent-type)
  1498. (guix-ui-read-package-profile)))
  1499. (guix-package-get-display profile 'dependent (or type 'all) packages))
  1500. ;;;###autoload
  1501. (defun guix-hidden-packages (&optional profile)
  1502. "Display hidden Guix packages.
  1503. If PROFILE is nil, use `guix-current-profile'."
  1504. (interactive (list (guix-ui-read-package-profile)))
  1505. (guix-package-get-display profile 'hidden))
  1506. ;;;###autoload
  1507. (defun guix-all-packages (&optional profile)
  1508. "Display all available Guix packages.
  1509. If PROFILE is nil, use `guix-current-profile'.
  1510. Interactively with prefix, prompt for PROFILE."
  1511. (interactive (list (guix-ui-read-package-profile)))
  1512. (guix-package-get-display profile 'all))
  1513. ;;;###autoload
  1514. (define-obsolete-function-alias 'guix-newest-packages
  1515. 'guix-all-packages "0.5.2")
  1516. ;;;###autoload
  1517. (defun guix-number-of-packages ()
  1518. "Display the number of available Guix packages.
  1519. This number includes the packages from GUIX_PACKAGE_PATH (see
  1520. Info node `(guix) Package Modules')."
  1521. (interactive)
  1522. (message "Total number of Guix packages: %d."
  1523. (guix-eval-read "(number-of-packages)")))
  1524. (provide 'guix-ui-package)
  1525. ;;; guix-ui-package.el ends here