guix-ui-profile.el 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. ;;; guix-ui-profile.el --- Interface for displaying profiles -*- lexical-binding: t -*-
  2. ;; Copyright © 2016–2017 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 'list' interface for displaying Guix profiles
  18. ;; with `guix-profiles' command.
  19. ;;
  20. ;; `guix-profiles' variable controls what profiles are displayed.
  21. ;;; Code:
  22. (require 'dash)
  23. (require 'bui)
  24. (require 'guix nil t)
  25. (require 'guix-profiles)
  26. (require 'guix-utils)
  27. (guix-define-groups profile)
  28. (defcustom guix-profiles
  29. (-filter #'file-exists-p
  30. (list guix-user-profile
  31. guix-system-profile))
  32. "List of profiles displayed by '\\[guix-profiles]' command."
  33. :type '(repeat file)
  34. :group 'guix-profile)
  35. (defun guix-profile->entry (profile)
  36. "Return 'guix-profile' entry by PROFILE file-name."
  37. `((id . ,profile)
  38. (profile . ,profile)
  39. (current . ,(guix-current-profile? profile))
  40. (number-of-packages . ,(guix-profile-number-of-packages
  41. profile))
  42. (number-of-generations . ,(guix-profile-number-of-generations
  43. profile))))
  44. (defun guix-profile-get-entries ()
  45. "Return 'guix-profile' entries."
  46. (mapcar #'guix-profile->entry guix-profiles))
  47. ;;; Profile 'list'
  48. (bui-define-interface guix-profile list
  49. :mode-name "Profile-List"
  50. :buffer-name "*Guix Profiles*"
  51. :get-entries-function 'guix-profile-get-entries
  52. :format '((current guix-profile-list-get-current 10 t)
  53. (profile bui-list-get-file-name 40 t)
  54. (number-of-packages nil 11 bui-list-sort-numerically-2
  55. :right-align t)
  56. (number-of-generations nil 14 bui-list-sort-numerically-3
  57. :right-align t))
  58. :titles '((number-of-packages . "Packages")
  59. (number-of-generations . "Generations"))
  60. :hint 'guix-profile-list-hint
  61. :sort-key '(profile))
  62. (let ((map guix-profile-list-mode-map))
  63. (define-key map (kbd "RET") 'guix-profile-list-show-packages)
  64. (define-key map (kbd "P") 'guix-profile-list-show-packages)
  65. (define-key map (kbd "G") 'guix-profile-list-show-generations)
  66. (define-key map (kbd "M") 'guix-profile-list-apply-manifest)
  67. (define-key map (kbd "c") 'guix-profile-list-set-current)
  68. ;; Unbind "i" as "Profile Info" interface is not defined.
  69. (define-key map (kbd "i") nil))
  70. (defvar guix-profile-list-default-hint
  71. '(("\\[guix-profile-list-show-packages]") " show packages;\n"
  72. ("\\[guix-profile-list-show-generations]") " show generations;\n"
  73. ("\\[guix-profile-list-set-current]") " set current profile;\n"))
  74. (defun guix-profile-list-hint ()
  75. (bui-format-hints
  76. guix-profile-list-default-hint
  77. bui-list-sort-hint
  78. bui-common-hint))
  79. (defun guix-profile-list-current-profile ()
  80. "Return file name of the current profile."
  81. ;; (bui-entry-value (bui-list-current-entry) 'profile)
  82. ;; Just get the ID, as currently ID is the profile file name.
  83. (bui-list-current-id))
  84. (declare-function guix-installed-packages "guix-ui-package" t)
  85. (declare-function guix-generations "guix-ui-generation" t)
  86. (declare-function guix-system-generations "guix-ui-system-generation" t)
  87. (declare-function guix-apply-manifest "guix-misc" t)
  88. (defun guix-profile-list-show-packages ()
  89. "Display packages installed in the current profile."
  90. (interactive)
  91. (guix-installed-packages (guix-package-profile
  92. (guix-profile-list-current-profile))))
  93. (defun guix-profile-list-show-generations ()
  94. "Display generations of the current profile."
  95. (interactive)
  96. (let ((profile (guix-profile-list-current-profile)))
  97. (if (guix-system-profile? profile)
  98. (guix-system-generations)
  99. (guix-generations (guix-generation-profile profile)))))
  100. (defun guix-profile-list-apply-manifest (file)
  101. "Apply manifest from FILE to the current profile."
  102. (interactive
  103. (list (guix-read-file-name "File with manifest: ")))
  104. (guix-apply-manifest (guix-package-profile
  105. (guix-profile-list-current-profile))
  106. file (current-buffer)))
  107. (defun guix-profile-list-get-current (value &optional _)
  108. "Return string from VALUE showing whether this profile is current."
  109. (if value "(current)" ""))
  110. (defun guix-profile-list-set-current ()
  111. "Set `guix-current-profile' to the profile on the current line."
  112. (interactive)
  113. (guix-set-current-profile (guix-profile-list-current-profile))
  114. ;; Now updating "Current" column is needed. It can be done simply by
  115. ;; reverting the buffer, but it should be more effective to reset
  116. ;; 'current' parameter for all entries and to redisplay the buffer
  117. ;; instead.
  118. (let* ((current-id (bui-list-current-id))
  119. (new-entries (mapcar
  120. (lambda (entry)
  121. (let ((id (bui-entry-id entry)))
  122. (cons `(current . ,(equal id current-id))
  123. (--remove-first (eq (car it) 'current)
  124. entry))))
  125. (bui-current-entries))))
  126. (setf (bui-item-entries bui-item)
  127. new-entries))
  128. (bui-redisplay))
  129. ;;; Interactive commands
  130. (defun guix-profiles-show ()
  131. "Display Guix profiles.
  132. Unlike `guix-profiles', this command always recreates
  133. `guix-profile-list-buffer-name' buffer."
  134. (interactive)
  135. (bui-list-get-display-entries 'guix-profile))
  136. ;;;###autoload
  137. (defun guix-profiles ()
  138. "Display Guix profiles.
  139. Switch to the `guix-profile-list-buffer-name' buffer if it
  140. already exists.
  141. Modify `guix-profiles' variable to add more profiles."
  142. (interactive)
  143. (guix-switch-to-buffer-or-funcall
  144. guix-profile-list-buffer-name #'guix-profiles-show 'message))
  145. (provide 'guix-ui-profile)
  146. ;;; guix-ui-profile.el ends here