Coverage report: /home/ellis/comp/core/lib/organ/graph.lisp
Kind | Covered | All | % |
expression | 0 | 364 | 0.0 |
branch | 0 | 12 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; graph.lisp --- Org Graph Lisp API
6
(in-package :organ/graph)
8
(load-database-backend :rdb)
11
(deftype org-id () `(octet-vector 16))
14
(defclass org-graph-schema (rdb-schema) ()
16
:fields (make-fields :file '(pathname . octet-vector)
17
:title '(org-id . string)
18
:hash '(org-id . string)
19
:atime '(org-id . octet-vector)
20
:mtime '(org-id . octet-vector)
21
:node '(org-id . octet-vector)
22
:edge '(org-id . octet-vector)
23
:node-tags '(org-id . string)
24
:node-links '(org-id . string)
25
:node-properties '(org-id . string)
26
:node-priority '(org-id . string)
27
:node-schedule '(org-id . string)
28
:node-file '(org-id . string)
29
:node-pos '(org-id . octet-vector)
30
:node-state '(org-id . string))))
32
(defparameter *org-graph-schema* (make-instance 'org-graph-schema))
34
(define-condition org-id-locations-out-of-sync (simple-error) ())
36
(defvar *org-graph-file* (merge-pathnames ".emacs.d/graph.sxp" (user-homedir-pathname)))
37
(defvar *org-id-locations-file* (merge-pathnames ".emacs.d/.org-id-locations" (user-homedir-pathname)))
40
(defun make-org-id-locations (&optional (file *org-id-locations-file*))
41
(let ((tbl (make-hash-table :test 'equal)))
42
(with-open-file (file file)
43
(dolist (entry (read file))
44
(if-let ((file (probe-file (car entry))))
45
(setf (gethash (namestring file) tbl) (cdr entry))
46
(signal 'org-id-locations-out-of-sync :format-control "~A" :format-arguments (list entry)))))
49
(defun uuid-octets* (id)
50
(handler-case (uuid-to-octet-vector id)
52
(sb-pcl::missing-slot () id)))
55
(defvar *org-graph* nil)
57
(defstruct org-graph nodes edges)
59
(defmethod read-ast ((fmt (eql :org-graph)) stream &key)
60
(let ((graph (apply 'make-org-graph (read stream))))
61
(setf #1=(org-graph-nodes graph)
62
(mapcar (lambda (x) (wrap (make-instance 'org-graph-node) x)) #1#)
63
#2=(org-graph-edges graph)
64
(mapcar (lambda (x) (wrap (make-instance 'org-graph-edge) x)) #2#))
67
(defmethod build-ast ((self org-graph) &key)
68
`(:nodes ,(mapcar 'build-ast (org-graph-nodes self))
69
:edges ,(mapcar 'build-ast (org-graph-edges self))))
71
(defun read-org-graph-file (&optional (file *org-graph-file*))
72
(with-open-file (f file) (read-ast :org-graph f)))
74
(defun init-org-graph ()
75
(setf *org-graph* (read-org-graph-file)))
77
(defclass org-graph-node (vertex)
78
((name :initarg :name :accessor name)
79
(path :initarg :path :accessor path)
80
(point :initarg :point :accessor idx)))
82
(defmethod wrap ((self org-graph-node) form)
83
(make-instance 'org-graph-node
84
:id (make-uuid-from-string (pop form)) :name (pop form) :path (pop form) :point (pop form)))
86
(defmethod build-ast ((self org-graph-node) &key)
87
`(,(uuid-to-string (id self)) ,(name self) ,(path self) ,(idx self)))
89
(defclass org-graph-edge (edge)
90
((type :initarg :type :accessor edge-type)
91
(properties :initarg :properties :accessor edge-properties)
92
(timestamp :initarg :timestamp :accessor timestamp)
93
(point :initarg :point :accessor idx)))
95
(defmethod wrap ((self org-graph-edge) form)
96
(make-instance 'org-graph-edge
98
:in (make-uuid-from-string (pop form))
99
:properties (pop form)
101
(destructuring-bind (sec minute hour day month year timezone a1 a2) (pop form)
102
(declare (ignore a1 a2))
103
(encode-timestamp 0 sec minute hour day month year :timezone (or timezone *default-timezone*)))
107
(defmethod build-ast ((self org-graph-edge) &key)
108
`(,(keywordicate (edge-type self)) ,(uuid-to-string (edge-in self)) ,(edge-properties self)
109
,(timestamp-to-universal (timestamp self)) ,(idx self) ,(format nil "~A" (edge-out self))))
111
(defstruct org-graph-file
112
"Internal helper struct used while processing files in the *ORG-GRAPH*."
113
path document timestamp hash)
115
(defun org-graph-extract-files (&optional (graph *org-graph*))
117
(dolist (n (remove-duplicates (org-graph-nodes graph) :test 'string= :key 'path) ret)
118
(push (wrap (make-org-graph-file) (probe-file (path n))) ret))))
120
(defmethod id ((self org-graph-file))
121
(org-graph-file-hash self))
123
(defmethod wrap ((self org-graph-file) (file pathname))
124
(setf (org-graph-file-hash self) (b3sum file)
125
(org-graph-file-path self) file
126
(org-graph-file-timestamp self) (universal-to-timestamp (file-write-date file))
127
(org-graph-file-document self) (organ:org-parse :document file))
130
(defmethod wrap ((self org-graph-file) (node org-graph-node))
131
(let ((file (path node)))
132
(setf (org-graph-file-hash self) (b3sum file)
133
(org-graph-file-path self) file
134
(org-graph-file-document self) (organ:org-parse :document file))
137
(defun insert-org-files ()
138
(log:info! "inserting org files")
140
(lambda (n) (insert-key *org-graph-db* (uuid-octets* (id n)) (path n) :column "file"))
141
(org-graph-nodes *org-graph*)))
143
(defun insert-org-nodes ()
144
(log:info! "inserting org nodes")
145
(dolist (id (mapcar 'id (org-graph-nodes *org-graph*)))
146
(insert-key *org-graph-db*
152
(defun insert-org-edges ()
153
(log:info! "inserting org edges")
154
(dolist (e (org-graph-edges *org-graph*))
155
(insert-key *org-graph-db*
156
(uuid-octets* (edge-in e))
157
(uuid-octets* (edge-out e))
161
;; while (iter-valid-p it)
162
;; do (log:info! (iter-key it) (iter-val it))
164
;; do (print (incf i))))
167
(defvar *org-graph-db-directory* (merge-pathnames ".store/db/graph/" (user-homedir-pathname)))
169
(defun make-org-graph-db ()
171
(make-db :rdb :name (namestring *org-graph-db-directory*)
172
:opts (default-rdb-opts))
175
(defvar *org-graph-db* nil)
177
(defun close-org-graph-db ()
178
(when (db-open-p *org-graph-db*)
179
(shutdown-db *org-graph-db*)))
181
(defun init-org-graph-db ()
182
(ensure-directories-exist
183
(make-pathname :directory (butlast (pathname-directory *org-graph-db-directory*)))
185
(with-db (db :open (not (db-open-p *org-graph-db*)) :close nil :db *org-graph-db*)
190
(log:info! "created org-graph-db" *org-graph-db* *org-graph-db-directory* *org-graph-schema*)))
192
(defun open-org-graph-db ()
193
(unless *org-graph* (init-org-graph))
194
(unless (probe-file *org-graph-db-directory*)
196
(if (and *org-graph-db* (db-open-p *org-graph-db*))
199
(load-opts *org-graph-db*)
200
(open-columns* *org-graph-db*))))
202
(defun destroy-org-graph-db ()
203
(unless (db-closed-p *org-graph-db*)
204
(close-db *org-graph-db*)
205
(log:info! "destroyed org-graph-db at ~A" *org-graph-db-directory*)))
207
(defun og-get (key &optional (from "node"))
208
(get-val *org-graph-db* key :data-type 'string :column from))
210
(defun og-values (column)
211
(with-iter (it (iter *org-graph-db* :column (find-column column *org-graph-db*)))
213
(loop while (iter-valid-p)
214
collect (cons (handler-case (octet-vector-to-uuid (key))
215
(simple-type-error () (sb-ext:octets-to-string (key))))
216
(sb-ext:octets-to-string (val)))
220
(defun org-graph-file-search (path &rest ids)
221
"Return a list of org headings corresponding to IDS in PATH."
222
;; first get an org-document and list of headings
223
(let* ((doc (organ:org-parse :document path))
224
(headings (organ:doc-tree doc))
226
;; map over IDs, searching for matches
227
(loop for h across headings
228
if (typep h 'organ:org-heading)
231
(when-let* ((prop (organ::org-properties h))
232
(id (find (print (value (find "ID" (print (organ:org-contents prop))
233
:key (lambda (x) (string-upcase (name x))))))
236
(removef ids id :test 'equal)
239
finally (return ret))))
242
(defmethod serialize ((self org-graph) format &key stream)
243
(serialize (build-ast self) format :stream stream))