arroyo/arroyo-utils.org

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)