Draft resource API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
diff --git a/resource.lisp b/resource.lisp
index 8793f89..818f84b 100644
--- a/resource.lisp
+++ b/resource.lisp
@@ -50,48 +50,25 @@
;; Resource
(defclass resource (standard-object)
- ((name :type t
+ ((name :type string
:initform (error "missing resource name")
- :initarg name
+ :initarg :name
:reader resource-name))
(:metaclass resource-class))
(defun make-resource (type name &rest properties)
- (apply #'make-instance type 'name name properties))
-
-;; Resource registration
-
-(defgeneric register-resource (resource))
-
-(defmethod register-resource ((res resource))
- "FIXME: lock instances index"
- (let ((name (resource-name res))
- (index (resource-class-instances (class-of res))))
- (assert (not (gethash name index)))
- (setf (gethash name index) res)))
-
-(defun define-resource (type name &rest properties)
- (let ((res (apply #'make-resource type name properties)))
- (register-resource res)
- res))
-
-(defgeneric find-resource (type name))
-
-(defmethod find-resource ((type class) (name string))
- (gethash name (resource-class-instances type)))
-
-(defmethod find-resource ((type symbol) name)
- (find-resource (find-class type) name))
+ (apply #'make-instance type :name name properties))
;; Resource property
(defun resource-property-slot-definition (resource property)
(declare (type resource resource)
(type symbol property))
- (find-if (lambda (slot)
- (let ((key (car (closer-mop:slot-definition-initargs slot))))
- (eq property key)))
- (closer-mop:class-slots (class-of resource))))
+ (or (find-if (lambda (slot)
+ (let ((key (car (closer-mop:slot-definition-initargs slot))))
+ (eq property key)))
+ (closer-mop:class-slots (class-of resource)))
+ (error "Property not found : ~S for ~S" property resource)))
(defun resource-property-slot-name (resource property)
(closer-mop:slot-definition-name
@@ -118,7 +95,8 @@
(defmethod resource-properties ((class resource-class))
(iter (for slot in (closer-mop:class-slots class))
(for key = (car (closer-mop:slot-definition-initargs slot)))
- (when (keywordp key)
+ (when (and (keywordp key)
+ (not (eq :name key)))
(collect key))))
(defmethod resource-properties ((res resource))
@@ -129,7 +107,8 @@
(let ((key (car (closer-mop:slot-definition-initargs slot)))
(name (closer-mop:slot-definition-name slot)))
(when (and (slot-boundp resource name)
- (keywordp key))
+ (keywordp key)
+ (not (eq :name key)))
(funcall fn key (slot-value resource name)))))
(closer-mop:class-slots (class-of resource))))
@@ -167,16 +146,20 @@
#1#
(write-char #\Space s)))))
-;; Gathering resource values
+;; Gathering resource properties
(defgeneric gather-resource-property (resource property))
+;; Gathering resources
+
(defgeneric gather-resource (type name))
(defmethod gather-resource ((resource resource) (name t))
(dolist (property (resource-properties resource))
- (setf (slot-value resource property)
- (gather-resource-property resource property)))
+ (if (slot-boundp resource property)
+ (slot-value resource property)
+ (setf (slot-value resource property)
+ (gather-resource-property resource property))))
resource)
(defmethod gather-resource ((type class) (name string))
@@ -187,6 +170,19 @@
(setq type (find-symbol (symbol-name type) :adams)))
(gather-resource (find-class type) name))
-;; Ensuring resource values
+;; Ensuring resource properties
+
+(defgeneric ensure-resource-property (spec property gathered))
+
+(defgeneric ensure-resource (spec))
-(defgeneric ensure-resource-property (resource property value))
+(defmethod ensure-resource ((resource resource))
+ (let ((gathered (gather-resource (class-of resource)
+ (resource-name resource))))
+ (mapcan-resource-properties
+ (lambda (property spec-value)
+ (unless (and (slot-boundp gathered property)
+ (equal spec-value
+ (slot-value gathered property)))
+ (ensure-resource-property spec property gathered)))
+ spec)))
diff --git a/unix.lisp b/unix.lisp
index 19f445e..64d0948 100644
--- a/unix.lisp
+++ b/unix.lisp
@@ -128,6 +128,20 @@
;; File
+(define-resource-class file ()
+ ((type :type symbol)
+ (permissions :type string)
+ (owner :type (or string fixnum))
+ (group :type (or string fixnum))
+ (size :type integer)
+ (atime :type integer)
+ (mtime :type integer)
+ (ctime :type integer)
+ (blocks :type integer)
+ (md5 :type string)
+ (sha1 :type string)
+ (content :type string)))
+
(define-constant +file-type-mode-bits+
'((:fifo . #o010000)
(:character-special . #o020000)
@@ -169,31 +183,39 @@
(values file dev ino mode nlink uid gid rdev size
atime mtime ctime blksize blocks flags))
-(define-resource-class file ()
- ((type :type symbol)
- (permissions :type string)
- (owner :type (or string fixnum))
- (group :type (or string fixnum))
- (size :type integer)
- (atime :type integer)
- (mtime :type integer)
- (ctime :type integer)
- (blocks :type integer)))
-
-(defmethod gather-resource ((resource file) name)
- (iterate (stat<1> (name* dev* ino* mode* nlink* uid* gid* rdev* size*
- atime* mtime* ctime* blksize* blocks* flags*)
- in (stat name))
- (when (string= name name*)
- (with-slots (type permissions owner group
- size atime mtime ctime blocks) resource
+(defun gather-file-stat (resource)
+ (with-slots (name type permissions owner group
+ size atime mtime ctime blocks) resource
+ (iterate (stat<1> (name* dev* ino* mode* nlink* uid* gid* rdev* size*
+ atime* mtime* ctime* blksize* blocks* flags*)
+ in (stat name))
+ (when (string= name name*)
(setf type (mode-file-type mode*)
permissions (mode-permissions mode*)
owner (gather-uid-user-name uid*)
group (gather-gid-group-name gid*)
size size* atime atime* mtime mtime* ctime ctime*
- blocks blocks*))
- (return resource))))
+ blocks blocks*)
+ (return resource)))))
+
+(define-syntax cksum<1> (algo sum file)
+ "(\\S+) \\((.*)\\) = (\\S+)"
+ "Syntax for cksum(1) output.")
+
+(defun gather-file-cksum (resource &rest algorithms)
+ (let ((name (resource-name resource)))
+ (iterate (cksum<1> (algo* file* sum*)
+ in (run "cksum -a ~{~A~^,~} ~A"
+ algorithms (sh-quote name)))
+ (for algo = (find algo* algorithms
+ :key #'symbol-name
+ :test #'string-equal))
+ (when (and algo (string= name file*))
+ (setf (resource-property resource algo) sum*))))
+ resource)
+
+(defmethod gather-resource ((resource file) name)
+ (gather-file-stat resource))
(defun permissions-mode-bits (s)
(declare (type (string 9) s))
@@ -207,3 +229,12 @@
(ecase (char s 6) (#\- 0) (#\r #o0004))
(ecase (char s 7) (#\- 0) (#\w #o0002))
(ecase (char s 8) (#\- 0) (#\x #o0001) (#\S #o1000) (#\s #o1001))))
+
+(defmethod (setf resource-property) :after ((value string)
+ (resource file)
+ (property (eql :content)))
+ (dolist (digest '(:md5 :sha1))
+ (setf (resource-property resource digest)
+ (ironclad:digest-sequence
+ digest
+ (trivial-utf-8:string-to-utf-8-bytes value)))))