aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2021-03-27 20:41:40 -0700
committerSean Whitton <spwhitton@spwhitton.name>2021-03-27 20:45:11 -0700
commita6b692fc167b8fa7fbdf4ac821fdb23a7295a8cc (patch)
treec6c34f9dcecb5911dd613f4464cae0b2f9f01c66
parent5239b8d8fd2cca9beccdc62e6a616816f8c5cf31 (diff)
downloadconsfigurator-a6b692fc167b8fa7fbdf4ac821fdb23a7295a8cc.tar.gz
add WITH-CHANGE-IF-CHANGES-FILE{,-CONTENT}
Signed-off-by: Sean Whitton <spwhitton@spwhitton.name>
-rw-r--r--doc/ideas.rst5
-rw-r--r--src/package.lisp2
-rw-r--r--src/property.lisp32
3 files changed, 34 insertions, 5 deletions
diff --git a/doc/ideas.rst b/doc/ideas.rst
index d32ffed..1209e7d 100644
--- a/doc/ideas.rst
+++ b/doc/ideas.rst
@@ -49,11 +49,6 @@ Core
calling its :HOSTATTRS subroutine too -- could we figure out catching and
ignoring the condition when its :HOSTATTRS subroutine did get run?
-- Macro for use in DEFPROP which works like Propellor's changesFile. Will
- probably output ``(:check ...)`` expression and then substitute user's code
- into a ``(:apply ...)`` expression. Use this or variants thereof in most of
- the entries in ``PROPERTY.FILE``.
-
- HOSTDEPLOY and HOSTDEPLOY-THESE functions which are like DEPLOY and
DEPLOY-THESE but take the CONNECTION argument from the :DEPLOY argument to
DEFHOST.
diff --git a/src/package.lisp b/src/package.lisp
index 5631860..efce2ee 100644
--- a/src/package.lisp
+++ b/src/package.lisp
@@ -130,6 +130,8 @@
#:assert-euid-root
#:assert-connection-supports
#:call-with-os
+ #:with-change-if-changes-file
+ #:with-change-if-changes-file-content
;; propspec.lisp
#:in-consfig
diff --git a/src/property.lisp b/src/property.lisp
index 7ff6c92..4403eb7 100644
--- a/src/property.lisp
+++ b/src/property.lisp
@@ -468,3 +468,35 @@ apply or unapply properties.")
(unless (or (eq type :posix) (lisp-connection-p))
(failed-change
"Cannot apply :LISP properties using a POSIX-type connection")))
+
+(defun cksum (file)
+ (ignore-errors (parse-integer (car (split-string (mrun "cksum" file))))))
+
+;; this is a safe parse of ls(1) output given its POSIX specification
+(defun ls-cksum (file)
+ (let ((ls (ignore-errors
+ (split-string (mrun :env '(:LOCALE "C") "ls" "-dlL" file))))
+ (cksum (cksum file)))
+ (when (and ls cksum)
+ (list* (car ls) cksum (subseq ls 2 8)))))
+
+(defmacro with-change-if-changes-file ((file) &body forms)
+ "Execute FORMS and yield :NO-CHANGE if FILE does not change.
+Since stat(1) is not POSIX, this is implemented by calling `ls -dlL' and
+cksum(1), and seeing if any of the information reported there, except for the
+number of links, has changed. Thus, you should not use this macro to detect
+changes in properties which will change the file but not the output of `ls
+-dlL' and cksum(1)."
+ (with-gensyms (before)
+ `(let* ((,before (ls-cksum ,file))
+ (result (progn ,@forms)))
+ (if (and ,before (equal ,before (ls-cksum ,file)))
+ :no-change result))))
+
+(defmacro with-change-if-changes-file-content ((file) &body forms)
+ "Execute FORMS and yield :NO-CHANGE if FILE has the same content afterwards."
+ (with-gensyms (before)
+ `(let* ((,before (cksum ,file))
+ (result (progn ,@forms)))
+ (if (and ,before (eql ,before (cksum ,file)))
+ :no-change result))))