232 lines
9.9 KiB
EmacsLisp
232 lines
9.9 KiB
EmacsLisp
;;; nix-store.el --- Run nix commands -*- lexical-binding: t -*-
|
|
|
|
;; Author: Matthew Bauer <mjbauer95@gmail.com>
|
|
;; Homepage: https://github.com/NixOS/nix-mode
|
|
;; Keywords: nix
|
|
;; Package-Requires: ((emacs "25.1") (magit-section "3.3.0"))
|
|
|
|
;; 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)
|
|
|
|
(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 ,value))
|
|
(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)
|
|
do
|
|
(magit-insert-section (store-path x)
|
|
(insert
|
|
(propertize x 'face (if exists 'nix-store-path-realised-face 'nix-store-path-unrealised-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
|
|
: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)
|
|
|
|
(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)
|
|
(let ((drv-path (car (nix-store-path-derivers nix-buffer-store-path))))
|
|
(if (not drv-path)
|
|
(message "This store path has no associated derivation.")
|
|
(find-file (nix-log-path drv-path)))))
|
|
|
|
(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"
|
|
(setq-local revert-buffer-function #'nix-store--revert-buffer-function)
|
|
(read-only-mode 1))
|
|
|
|
(provide 'nix-store)
|
|
;;; nix-store.el ends here
|