-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
nix-store.el
239 lines (205 loc) · 10.2 KB
/
nix-store.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
;;; nix-store.el --- Run nix commands -*- lexical-binding: t -*-
;; Author: Matthew Bauer <mjbauer95@gmail.com>
;; Homepage: https://github.com/NixOS/nix-mode
;; Keywords: nix
;; This file is NOT part of GNU Emacs.
;;; Commentary:
;;; Code:
(require 'eieio)
(require 'nix)
(require 'nix-log)
(require 'magit-section)
(eval-when-compile
(require 'cl-lib))
(defgroup nix-store nil
"Nix-store customizations."
:group 'nix)
(defcustom nix-store-path-omit-self t
"Do not list the current entry itself within sections of `nix-store-path-mode'."
:package-version '(nix-mode . "1.6.0")
:type 'boolean)
(defun nix-store-realise (path)
"Realise a path asynchronously.
PATH the path within /nix/store to realise"
(make-process
:buffer nil
:command (list nix-store-executable "--realise" path)
:noquery t
:name (format "*nix-store*<%s>" path)))
(defvar-local nix-buffer-store-path nil "Buffer-local object holding an `nix-store-path` object.")
(defclass nix-store-path ()
((path :initarg :path :accessor nix-store-path-path)
(status :initarg :status :accessor nix-store-path-status)
(hash :initarg :hash :accessor nix-store-path-hash)
(size :initarg :size :accessor nix-store-path-size)
(derivers :initarg :derivers :accessor nix-store-path-derivers)
(outputs :initarg :outputs :accessor nix-store-path-outputs)
(references :initarg :references :accessor nix-store-path-references)
(referrers :initarg :referrers :accessor nix-store-path-referrers)
(requisites :initarg :requisites :accessor nix-store-path-requisites))
"Nix-Store-Path Class holds all information of the path that
is displayed")
(cl-defmethod nix-store-fill-data ((object nix-store-path))
"Query the nix store via `nix-store-executable' and save that data into OBJECT."
(oset object :size (nix-store--query 'size (nix-store-path-path object)))
(oset object :hash (nix-store--query 'hash (nix-store-path-path object)))
(oset object :derivers (nix-store--query 'deriver (nix-store-path-path object)))
(oset object :outputs (nix-store--query 'outputs (nix-store-path-path object)))
(oset object :referrers (nix-store--query 'referrers (nix-store-path-path object)))
(oset object :requisites (nix-store--query 'requisites (nix-store-path-path object)))
(oset object :references (nix-store--query 'references (nix-store-path-path object)))
(oset object :status (file-exists-p (car (nix-store-path-outputs object))))
object)
(cl-defun nix-store--query (argument &optional (path (nix-store-path-path nix-buffer-store-path)))
"Query the nix-store for information.
ARGUMENT is given to the executable as an argument. See
nix-store(1) for possibilities. PATH is the store object that is
being queried. Runs `nix-store-executable' to get that
information."
(let ((nix-executable nix-store-executable))
(cond
((eq 'deriver argument)
;; Special treatment for 'derivers', we want to treat a single entry
;; with this string as an empty list
(remove "unknown-deriver"
(nix--process-lines "--query" "--deriver" path )))
((eq 'size argument) (string-to-number (nix--process-string "--query" "--size" path )))
((eq 'hash argument) (nix--process-string "--query" "--hash" path ))
((eq 'requisites argument) (nix--process-lines "--query" "--requisites" path ))
((eq 'references argument) (nix--process-lines "--query" "--references" path ))
((eq 'referrers argument) (nix--process-lines "--query" "--referrers" path ))
((eq 'outputs argument)
(ignore-errors
;; This can fail for non-derivation paths
(nix--process-lines "--query" "--outputs" path )))
(t (error "Unknown argument to nix-store --query: %s" argument)))))
(cl-defun nix-store-path-insert-path (&optional (store-path nix-buffer-store-path))
"Insert a section showing the path of STORE-PATH."
(magit-insert-section (path (nix-store-path-path store-path))
(magit-insert-heading (propertize (format "%-11s" "Path:") 'face 'magit-section-heading)
(propertize (oref store-path path)
'face (if (file-exists-p (nix-store-path-path store-path))
'nix-store-path-realised-face
'nix-store-path-unrealised-face) ))))
(cl-defun nix-store-path-insert-size (&optional (store-path nix-buffer-store-path))
"Insert a section showing the size of STORE-PATH."
(magit-insert-section (size (nix-store-path-size store-path))
(magit-insert-heading (propertize (format "%-11s" "Size:") 'face 'magit-section-heading)
(format "%s" (oref store-path size)))))
(cl-defun nix-store-path-insert-hash (&optional (store-path nix-buffer-store-path))
"Insert a section showing the hash of STORE-PATH."
(magit-insert-section (hash (nix-store-path-hash store-path))
(magit-insert-heading (propertize (format "%-11s" "Hash:") 'face 'magit-section-heading)
(format "%s" (oref store-path hash)))))
(cl-defun nix-store-path-insert-status (&optional (store-path nix-buffer-store-path))
"Insert a section showing the status of STORE-PATH."
(magit-insert-section (status (nix-store-path-status store-path))
(magit-insert-heading (propertize (format "%-11s" "Status:") 'face 'magit-section-heading)
(if (nix-store-path-status store-path) "realised" "unrealised"))))
(defmacro nix-store--magit-insert-section-list (type value label)
"Helper macro for inserting a list as a magit-section.
TYPE and VALUE will be used as the type and value of the section
respectively. The LABEL is the text displayed."
`(let ((value (cl-remove
(and nix-store-path-omit-self (nix-store-path-path nix-buffer-store-path))
,value :test #'equal)))
(when (and (listp value) (> (length value) 0))
(magit-insert-section (,type value)
(magit-insert-heading ,label)
(cl-loop for x in value
for exists = (file-exists-p x)
for face = (if exists 'nix-store-path-realised-face 'nix-store-path-unrealised-face)
do
(magit-insert-section (store-path x)
(insert (propertize x 'face face) ?\n)))
(insert ?\n)
(magit-insert-child-count (magit-current-section))))))
(cl-defun nix-store-path-insert-derivers (&optional (store-path nix-buffer-store-path))
"Insert sections showing all derivers of STORE-PATH."
(nix-store--magit-insert-section-list derivers (nix-store-path-derivers store-path) "Derivers:"))
(cl-defun nix-store-path-insert-outputs (&optional (store-path nix-buffer-store-path))
"Insert sections showing all outputs of STORE-PATH."
(nix-store--magit-insert-section-list outputs (nix-store-path-outputs store-path) "Outputs:"))
(cl-defun nix-store-path-insert-references (&optional (store-path nix-buffer-store-path))
"Insert sections showing all references of STORE-PATH."
(nix-store--magit-insert-section-list references (nix-store-path-references store-path) "References:"))
(cl-defun nix-store-path-insert-referrers (&optional (store-path nix-buffer-store-path))
"Insert sections showing all referrers of STORE-PATH."
(nix-store--magit-insert-section-list referrers (nix-store-path-referrers store-path) "Referrers:"))
(cl-defun nix-store-path-insert-requisites (&optional (store-path nix-buffer-store-path))
"Insert sections showing all requisites of STORE-PATH."
(nix-store--magit-insert-section-list requisites (nix-store-path-requisites store-path) "Requisites:"))
(defcustom nix-store-path-headers-hook
'(nix-store-path-insert-path
nix-store-path-insert-status
nix-store-path-insert-hash
nix-store-path-insert-size)
"Hook run to insert headers into the nix-store buffer.
A list of function that each take one argument, the store path object."
:group 'nix-store
:type 'hook
:package-version '(nix-mode . "1.5.0")
:options '(nix-store-path-insert-path
nix-store-path-insert-status
nix-store-path-insert-hash
nix-store-path-insert-size))
(defcustom nix-store-path-sections-hook
'(nix-store-path-insert-derivers
nix-store-path-insert-outputs
nix-store-path-insert-references
nix-store-path-insert-referrers
nix-store-path-insert-requisites)
"Hook run to insert sections into a nix-store buffer.
A list of function that each take one argument, the store path object."
:group 'nix-store
:type 'hook
:package-version '(nix-mode . "1.5.0"))
(defun nix-store-show-path (path)
"Show a nix-store PATH.
If you want to change the order of the section lists (or even
implement your own ones) you can customize the variable
`nix-store-path-headers-hook' and
`nix-store-path-sections-hook'."
(interactive "FNix-Store-Path: ")
(setq path (expand-file-name path default-directory))
(switch-to-buffer (format "Nix Store Path: %s" path))
(nix-store-path-mode)
(setq nix-buffer-store-path (nix-store-fill-data (make-instance 'nix-store-path :path path))
list-buffers-directory path)
(when (file-directory-p path)
(setq default-directory path))
(let ((inhibit-read-only t))
(erase-buffer)
(magit-insert-section (store-path)
(magit-insert-headers 'nix-store-path-headers-hook)
(magit-run-section-hook 'nix-store-path-sections-hook))
(goto-char (point-min))))
(defun nix-store-path-at-point ()
"Return the nix-store path at point."
;; TODO extract this via magit-section values
(substring-no-properties (thing-at-point 'filename)))
(defun nix-store-show-path-at-point ()
"Opens the nix-store-path at point.
It uses \\[nix-store-show-path] to display the store path."
(interactive)
(nix-store-show-path (nix-store-path-at-point)))
(defun nix-store-show-log ()
"Opens the log file for the derivation of the nix-store path."
(interactive)
(if-let ((drv-path (car (nix-store-path-derivers nix-buffer-store-path))))
(find-file (nix-log-path drv-path))
(user-error "This store path has no associated derivation.")))
(defvar nix-store-path-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "RET") 'nix-store-show-path-at-point)
(define-key map (kbd "l") 'nix-store-show-log)
map))
(defun nix-store--revert-buffer-function (&rest _ignore)
"Helper function to be called by `revert-buffer'."
(nix-store-show-path (nix-store-path-path nix-buffer-store-path)))
(define-derived-mode nix-store-path-mode magit-section-mode "Nix Store Path"
:group 'nix-store
(setq-local revert-buffer-function #'nix-store--revert-buffer-function)
(read-only-mode 1))
(provide 'nix-store)
;;; nix-store.el ends here