5.1 KiB
Utilities for Arroyo Systems Generation
NEXT Arroyo minor-mode
NEXT Menu Bar entries in org-mode
buffers
- flood
- build
- sqlite
- update db
NEXT yasnippets for common document patterns
- inserting the keywords for the generators
Arroyo Dependency Sorting
Arroyo uses tsort
from GNU Coreutils to order dependencies, because let's face it: implementing data structures is not the sort of fun I want to have. home-manager itself has a small DAG topological sort implementation which I could probably use as a base to port across, but I could also shell out to coreutils. I think it's fair to make GNU coreutils a dependency to the emacs arroyo subsystems… Previous generations used a simple CCE_PRIORITY
keyword and a general ordering scheme which I tried to manage on my own. I think doing a true topological sort will be much better than this.
ARROYO_MODULE_WANTS
will be a keyword whose value is a another arroyo file, relative to org-roam-directory
, which the module requires to be loaded beforehand. This is only used in the Arroyo Emacs Generator at the moment as Nix can handle its own resolution. it can be specified multiple times for multiple dependencies.
(add-to-list 'arroyo-db-keywords "ARROYO_MODULE_DEP" nil #'equal)
(add-to-list 'arroyo-db-keywords "ARROYO_MODULE_WANTS" nil #'equal)
(add-to-list 'arroyo-db-keywords "ARROYO_MODULE_WANTED" nil #'equal)
Arroyo uses tsort
to order the deps; this is really decomposed and should be started with arroyo-utils-order-modules
to read it.
(defun arroyo-utils--format-dep-pairs (line-fmt final-fmt want-rows wanted-rows)
(->> (append (-map (pcase-lambda (`(,file ,keyword ,value))
(list (file-relative-name file org-roam-directory) value))
want-rows)
(-map (pcase-lambda (`(,file ,keyword ,value))
(list value (file-relative-name file org-roam-directory)))
wanted-rows))
(-map (pcase-lambda (`(,thing ,dep))
(format line-fmt dep thing)))
(s-join "\n")
(format final-fmt)))
(defun arroyo-utils--filter-files (rows files)
(-filter (pcase-lambda (`(,file ,keyword, value))
(or (not files)
(-contains? files file)))
rows))
(defun arroyo-utils--order-command (want-rows wanted-rows)
(arroyo-utils--format-dep-pairs "%s %s" "tsort <<EOF\n%s\nEOF"
want-rows wanted-rows))
(defun arroyo-utils-order-modules (&optional files skip-cmd)
(let* ((want-rows
(arroyo-utils--filter-files
(arroyo-db-query [:select [file keyword value] :from keywords
:where (in keyword $v1)]
(vector "ARROYO_MODULE_DEP" "ARROYO_MODULE_WANTS"))
files))
(wanted-rows
(arroyo-utils--filter-files
(arroyo-db-query [:select [file keyword value] :from keywords
:where (= keyword "ARROYO_MODULE_WANTED")])
files))
(wanted-files (-map #'car wanted-rows))
(want-files (-map #'car want-rows))
(missing
(-difference files (-union wanted-files want-files)))
(cmd (arroyo-utils--order-command want-rows wanted-rows)))
(if skip-cmd
cmd
(append
(->> cmd
(shell-command-to-string)
(s-split "\n")
(-remove #'string-empty-p))
missing))))
generate a dependency graph, this is quite similar to the order-command
function above:
(defun arroyo-utils--gen-digraph (want-rows wanted-rows)
(arroyo-utils--format-dep-pairs "\"%2s\" -> \"%1s\";" "digraph {\n%s\n}"
want-rows wanted-rows))
(defun arroyo-utils--write-digraph (contents &optional file)
(let ((file (or file "/tmp/arroyo.dot")))
(with-current-buffer (find-file-noselect file)
(erase-buffer)
(insert contents)
(save-buffer))
file))
(defun arroyo-utils-module-digraph ()
(interactive)
(let* ((want-rows (arroyo-db-query [:select [file keyword value] :from keywords
:where (in keyword $v1)]
(vector "ARROYO_MODULE_DEP" "ARROYO_MODULE_WANTS")))
(wanted-rows (arroyo-db-query [:select [file keyword value] :from keywords
:where (= keyword "ARROYO_MODULE_WANTED")])))
(->> (arroyo-utils--gen-digraph want-rows wanted-rows)
(arroyo-utils--write-digraph)
(find-file))))
Footmatter
(provide 'arroyo-utils)