git.fiddlerwoaroof.com
Raw Blame History
(in-package :alimenta.feed-archive.tools)

(defgeneric store (item directory)
  (:documentation "Store an item in a directory"))

(defmacro -> (&rest forms)
  (let ((forms (mapcar (lambda (form)
			 (typecase form
			   (list form)
			   (t (list form))))
		       forms)))
    (loop with result = (car forms)
       for form in (cdr forms)
       do
	 (setf result `(,(car form)
			 ,result
			 ,@(cdr form)))
       finally
	 (return result))))

(defun fix-pathname ()
  (let ((restart (find-restart 'fix-pathname)))
    (when restart
      (invoke-restart restart))))

(defun sha256-string (string)
  (let* ((digester (ironclad:make-digesting-stream :sha256))
	 (digest-stream (flexi-streams:make-flexi-stream digester)))
    (princ string digest-stream)
    (crypto:byte-array-to-hex-string
     (crypto:produce-digest
      digester))))

(defgeneric get-id (feed)
  (:documentation "Get an identifier for a feed"))

(defmethod get-id ((feed alimenta:feed))
  (let* ((link (alimenta:feed-link feed))
	 (host (puri:uri-host link)))
    (concat host "-" (sha256-string link) "/")))

(defmethod get-id ((item alimenta:item))
  (concatenate 'string
	       (local-time:format-timestring nil (alimenta:date item))
	       "-"
	       (sha256-string (alimenta:id item))))

(defun older-than-a-month (date)
  (let ((month-ago (local-time:timestamp- (local-time:now)
					  31 :day)))
    (if date
        (local-time:timestamp< date month-ago)
        t)))

(defun older-than-a-week (date)
  (let ((week-ago (local-time:timestamp- (local-time:now)
                                         7 :day)))
    (local-time:timestamp< date week-ago)))

(defmacro restart-once ((restart-name (&rest restart-args) &body handler) &body body)
  "Defines a restart that, the first time it's executed, runs a chunk of code and then,
next time, it re-raises the exception."
  (with-gensyms (start restarted)
    `(let ((,restarted nil))
       (tagbody ,start
	        (restart-case
	            (progn ,@body)
	          (,restart-name ,restart-args
	            ,@handler
	            (unless ,restarted
		            (setf ,restarted t)
		            (go ,start))))))))


(defun relative-uri-p (uri)
  (let ((uri (fw.lu:may (puri:uri uri))))
    (and uri
         (not
          (and (puri:uri-scheme uri)
               (puri:uri-host uri)
               t)))))

(defun coerce-feed-link (link feed)
  (flet ((unrelativize (url)
           (puri:render-uri (puri:merge-uris url
                                             link)
                            nil)))
    (prog1 feed
      (unless (and (alimenta:feed-link feed)
                   (not (relative-uri-p (alimenta:feed-link feed))))
        (setf (alimenta:feed-link feed)
              (if (alimenta:feed-link feed)
                  (unrelativize (alimenta:feed-link feed))
                  link)))
      (when (relative-uri-p (alimenta:link feed))
        (setf (alimenta:link feed)
              (unrelativize (alimenta:link feed)))))))

(defmacro with-retry ((&optional (message "retry the operation")) &body body)
  `(loop
     (restart-case (return (progn ,@body))
	     (retry ()
	       :report (lambda (s)
		               (format s "~@<~a~@:>" ,message))))))