arroyo/arroyo-utils.org

124 lines
5.1 KiB
Org Mode

:PROPERTIES:
:ID: arroyo/utils
:END:
#+TITLE: Utilities for Arroyo Systems Generation
#+filetags: :Project:Arroyo:Development:
#+PROPERTY: header-args:emacs-lisp :tangle arroyo-utils.el :comments link
#+AUTO_TANGLE: t
#+ARCOLOGY_KEY: cce/arroyo/utilities
#+ARCOLOGY_ALLOW_CRAWL: t
* 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
:PROPERTIES:
:ID: 4d62fe38-8611-4794-b2cf-b9900ff3294b
:END:
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. [[id:cce/home-manager][home-manager]] itself has a [[https://github.com/nix-community/home-manager/blob/master/modules/lib/dag.nix][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 [[id:arroyo/emacs][Arroyo Emacs Generator]] at the moment as Nix can handle its own resolution. it can be specified multiple times for multiple dependencies.
#+begin_src emacs-lisp :results none
(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)
#+end_src
Arroyo uses =tsort= to order the deps; this is really decomposed and should be started with =arroyo-utils-order-modules= to read it.
#+begin_src emacs-lisp :results none
(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))))
#+end_src
generate a dependency graph, this is quite similar to the =order-command= function above:
#+begin_src emacs-lisp
(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))))
#+end_src
* Footmatter
#+begin_src emacs-lisp
(provide 'arroyo-utils)
#+end_src