emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

scratch/sqlite 167278e 2/2: Implement a simple file-based multisesson st


From: Lars Ingebrigtsen
Subject: scratch/sqlite 167278e 2/2: Implement a simple file-based multisesson storage
Date: Mon, 13 Dec 2021 21:03:22 -0500 (EST)

branch: scratch/sqlite
commit 167278eb608541785871471c5cde7c7644c94e84
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Implement a simple file-based multisesson storage
---
 lisp/emacs-lisp/multisession.el            | 86 ++++++++++++++++++++++++++++++
 test/lisp/emacs-lisp/multisession-tests.el | 32 ++++++++++-
 2 files changed, 116 insertions(+), 2 deletions(-)

diff --git a/lisp/emacs-lisp/multisession.el b/lisp/emacs-lisp/multisession.el
index a75134f..a020bb2 100644
--- a/lisp/emacs-lisp/multisession.el
+++ b/lisp/emacs-lisp/multisession.el
@@ -212,6 +212,92 @@ DOC should be a doc string, and ARGS are keywords as 
applicable to
                   "delete from multisession where package = ? and key = ?"
                   id))
 
+;; Files Backend
+
+(defun multisession--encode-file-name (name)
+  (url-hexify-string name))
+
+(defun multisession--update-file-value (file object)
+  (with-temp-buffer
+    (let* ((time (file-attribute-modification-time
+                  (file-attributes file)))
+           (coding-system-for-read 'utf-8))
+      (insert-file-contents file)
+      (let ((stored (read (current-buffer))))
+        (setf (multisession--cached-value object) stored
+              (multisession--cached-sequence object) time)
+        stored))))
+
+(defun multisession--object-file-name (object)
+  (expand-file-name
+   (concat "files/"
+           (multisession--encode-file-name
+            (symbol-name (multisession--package object)))
+           "/"
+           (multisession--encode-file-name
+            (symbol-name (multisession--key object)))
+           ".value")
+   multisession-directory))
+
+(cl-defmethod multisession-backend-value ((_type (eql files)) object)
+  (let ((file (multisession--object-file-name object)))
+    (cond
+     ;; We have no value yet; see whether it's stored.
+     ((markerp (multisession--cached-value object))
+      (if (file-exists-p file)
+          (multisession--update-file-value file object)
+        ;; Nope; return the initial value.
+        (multisession--initial-value object)))
+     ;; We have a value, but we want to update in case some other
+     ;; Emacs instance has updated.
+     ((multisession--synchronized object)
+      (if (and (file-exists-p file)
+               (time-less-p (multisession--cached-sequence object)
+                            (file-attribute-modification-time
+                             (file-attributes file))))
+          (multisession--update-file-value file object)
+        ;; Nothing, return the cached value.
+        (multisession--cached-value object)))
+     ;; Just return the cached value.
+     (t
+      (multisession--cached-value object)))))
+
+(cl-defmethod multisession--backend-set-value ((_type (eql files))
+                                               object value)
+  (let ((file (multisession--object-file-name object))
+        (time (current-time)))
+    ;; Ensure that the directory exists.
+    (let ((dir (file-name-directory file)))
+      (unless (file-exists-p dir)
+        (make-directory dir t)))
+    (with-temp-buffer
+      (prin1 value (current-buffer))
+      (let ((coding-system-for-write 'utf-8))
+        (write-region (point-min) (point-max) file nil 'silent)))
+    (setf (multisession--cached-sequence object) time
+          (multisession--cached-value object) value)))
+
+(cl-defmethod multisession--backend-values ((_type (eql files)))
+  (mapcar (lambda (file)
+            (let ((bits (file-name-split file)))
+              (list (car (last bits 1))
+                    (file-name-sans-extension (car (last bits)))
+                    (with-temp-buffer
+                      (let ((coding-system-for-read 'utf-8))
+                        (insert-file-contents file)
+                        (read (current-buffer)))))))
+          (directory-files-recursively
+           (expand-file-name "files" multisession-directory)
+           "\\.value\\'")))
+
+(cl-defmethod multisession--backend-delete ((_type (eql files)) id)
+  (let ((file (multisession--object-file-name
+               (make-instance 'multisession
+                              :package (car id)
+                              :key (cadr id)))))
+    (when (file-exists-p file)
+      (delete-file file))))
+
 ;; (define-multisession-variable foo 'bar)
 ;; (multisession-value foo)
 ;; (multisession--set-value foo 'zot)
diff --git a/test/lisp/emacs-lisp/multisession-tests.el 
b/test/lisp/emacs-lisp/multisession-tests.el
index c08fa20..94db552 100644
--- a/test/lisp/emacs-lisp/multisession-tests.el
+++ b/test/lisp/emacs-lisp/multisession-tests.el
@@ -26,7 +26,7 @@
 (require 'ert-x)
 (require 'cl-lib)
 
-(ert-deftest multi-test-simple ()
+(ert-deftest multi-test-sqlite-simple ()
   (skip-unless (sqlite-available-p))
   (ert-with-temp-file dir
     :directory t
@@ -57,7 +57,7 @@
         (sqlite-close multisession--db)
         (setq multisession--db nil)))))
 
-(ert-deftest multi-test-busy ()
+(ert-deftest multi-test-sqlite-busy ()
   (skip-unless (and t (sqlite-available-p)))
   (ert-with-temp-file dir
     :directory t
@@ -96,4 +96,32 @@
         (sqlite-close multisession--db)
         (setq multisession--db nil)))))
 
+(ert-deftest multi-test-files-simple ()
+  (ert-with-temp-file dir
+    :directory t
+    (let ((user-init-file "/tmp/sfoo.el")
+          (multisession-storage 'files)
+          (multisession-directory dir))
+      (define-multisession-variable sfoo 0
+        ""
+        :synchronized t)
+      (should (= (multisession-value sfoo) 0))
+      (cl-incf (multisession-value sfoo))
+      (should (= (multisession-value sfoo) 1))
+      (call-process
+       (concat invocation-directory invocation-name)
+       nil t nil
+       "-Q" "-batch"
+       "--eval" (prin1-to-string
+                 `(progn
+                    (require 'multisession)
+                    (let ((multisession-directory ,dir)
+                          (multisession-storage 'files)
+                          (user-init-file "/tmp/sfoo.el"))
+                      (define-multisession-variable sfoo 0
+                        ""
+                        :synchronized t)
+                      (cl-incf (multisession-value sfoo))))))
+      (should (= (multisession-value sfoo) 2)))))
+
 ;;; multisession-tests.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]