guix-commits
[Top][All Lists]
Advanced

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

[no subject]


From: Mathieu Othacehe
Date: Tue, 2 Feb 2021 05:59:38 -0500 (EST)

branch: master
commit f8ddf8ca096ae099828b4fb916326fbac12d3a26
Author: Mathieu Othacehe <othacehe@gnu.org>
AuthorDate: Tue Feb 2 11:58:29 2021 +0100

    Add basic RSS support.
    
    * src/cuirass/rss.scm: New file.
    * Makefile.am (dist_pkgmodule_DATA): Add it.
    * src/cuirass/http.scm (url-handler): Add "/events/rss" route.
---
 Makefile.am          |   1 +
 src/cuirass/http.scm |   9 +++
 src/cuirass/rss.scm  | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 188 insertions(+)

diff --git a/Makefile.am b/Makefile.am
index 2a4ed30..9cc0bb2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,6 +57,7 @@ dist_pkgmodule_DATA =                         \
   src/cuirass/remote.scm                       \
   src/cuirass/remote-server.scm                        \
   src/cuirass/remote-worker.scm                        \
+  src/cuirass/rss.scm                          \
   src/cuirass/send-events.scm                  \
   src/cuirass/ui.scm                           \
   src/cuirass/utils.scm                                \
diff --git a/src/cuirass/http.scm b/src/cuirass/http.scm
index fd63c7d..743756d 100644
--- a/src/cuirass/http.scm
+++ b/src/cuirass/http.scm
@@ -29,6 +29,7 @@
   #:use-module (cuirass utils)
   #:use-module (cuirass logging)
   #:use-module (cuirass remote)
+  #:use-module (cuirass rss)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-11)
   #:use-module (srfi srfi-26)
@@ -660,6 +661,14 @@ Hydra format."
               (respond-json-with-error 500 "No build found.")))
            (respond-json-with-error 500 "Query parameter not provided."))))
 
+    (('GET "events" "rss")
+     (let* ((params (request-parameters request)))
+       (respond-html (rss-feed (db-get-builds `((weather . new)
+                                                (nr . 100)
+                                                (order . evaluation)
+                                                ,@params))
+                               #:params params))))
+
     (('GET "workers")
      (respond-html
       (html-page
diff --git a/src/cuirass/rss.scm b/src/cuirass/rss.scm
new file mode 100644
index 0000000..b5e8797
--- /dev/null
+++ b/src/cuirass/rss.scm
@@ -0,0 +1,178 @@
+;;; rss.scm -- RSS feed builder.
+;;; Copyright © 2021 Mathieu Othacehe <othacehe@gnu.org>
+;;;
+;;; This file is part of Cuirass.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (cuirass rss)
+  #:use-module (cuirass database)
+  #:use-module (srfi srfi-19)
+  #:use-module (srfi srfi-26)
+  #:use-module (sxml simple)
+  #:use-module (ice-9 hash-table)
+  #:use-module (ice-9 match)
+  #:export (rss-feed))
+
+;; This module is inspired by the (haunt builder rss) module that is part of
+;; the Haunt static site generator and writen by Christopher Lemmer Webber.
+
+(define %void-elements
+  '(area
+    base
+    br
+    col
+    command
+    embed
+    hr
+    img
+    input
+    keygen
+    link
+    meta
+    param
+    source
+    track
+    wbr))
+
+(define (void-element? tag)
+  "Return #t if TAG is a void element."
+  (pair? (memq tag %void-elements)))
+
+(define %escape-chars
+  (alist->hash-table
+   '((#\" . "quot")
+     (#\& . "amp")
+     (#\< . "lt")
+     (#\> . "gt"))))
+
+(define (string->escaped-html s port)
+  "Write the HTML escaped form of S to PORT."
+  (define (escape c)
+    (let ((escaped (hash-ref %escape-chars c)))
+      (if escaped
+          (format port "&~a;" escaped)
+          (display c port))))
+  (string-for-each escape s))
+
+(define (object->escaped-html obj port)
+  "Write the HTML escaped form of OBJ to PORT."
+  (string->escaped-html
+   (call-with-output-string (cut display obj <>))
+   port))
+
+(define (attribute-value->html value port)
+  "Write the HTML escaped form of VALUE to PORT."
+  (if (string? value)
+      (string->escaped-html value port)
+      (object->escaped-html value port)))
+
+(define (attribute->html attr value port)
+  "Write ATTR and VALUE to PORT."
+  (format port "~a=\"" attr)
+  (attribute-value->html value port)
+  (display #\" port))
+
+(define (element->html tag attrs body port)
+  "Write the HTML TAG to PORT, where TAG has the attributes in the
+list ATTRS and the child nodes in BODY."
+  (format port "<~a" tag)
+  (for-each (match-lambda
+              ((attr value)
+               (display #\space port)
+               (attribute->html attr value port)))
+            attrs)
+  (if (and (null? body) (void-element? tag))
+      (display " />" port)
+      (begin
+        (display #\> port)
+        (for-each (cut sxml->html <> port) body)
+        (format port "</~a>" tag))))
+
+(define (doctype->html doctype port)
+  (format port "<!DOCTYPE ~a>" doctype))
+
+(define* (sxml->html tree #:optional (port (current-output-port)))
+  "Write the serialized HTML form of TREE to PORT."
+  (match tree
+    (() *unspecified*)
+    (('doctype type)
+     (doctype->html type port))
+    (((? symbol? tag) ('@ attrs ...) body ...)
+     (element->html tag attrs body port))
+    (((? symbol? tag) body ...)
+     (element->html tag '() body port))
+    ((nodes ...)
+     (for-each (cut sxml->html <> port) nodes))
+    ((? string? text)
+     (string->escaped-html text port))
+    ;; Render arbitrary Scheme objects, too.
+    (obj (object->escaped-html obj port))))
+
+(define (sxml->html-string sxml)
+  "Render SXML as an HTML string."
+  (call-with-output-string
+    (lambda (port)
+      (sxml->html sxml port))))
+
+(define (date->rfc822-str date)
+  (date->string date "~a, ~d ~b ~Y ~T ~z"))
+
+(define* (build->rss-item build)
+  "Convert BUILD into an RSS <item> node."
+  (let* ((id       (assq-ref build #:id))
+         (job-name (assq-ref build #:job-name))
+         (specification (assq-ref build #:specification))
+         (weather  (assq-ref build #:weather))
+         (weather-text (cond
+                        ((= weather (build-weather new-success))
+                         "fixed")
+                        ((= weather (build-weather new-failure))
+                         "broken")))
+         (stoptime (assq-ref build #:stoptime)))
+    `(item
+      (title
+       ,(format #f "Build ~a on ~a is ~a."
+                job-name specification weather-text))
+      (author "Cuirass")
+      (pubDate ,(date->rfc822-str
+                 (time-utc->date
+                  (make-time time-utc 0 stoptime))))
+      (link "../../build/" ,id "/details")
+      (description
+       ,(sxml->html-string
+         `(p "The build " (b ,job-name) " for specification "
+             (b ,specification) " is " ,weather-text ".
+You can find the detailed information about this build "
+             (a (@ (href ,(string-append "../../build/"
+                                         (number->string id)
+                                         "/details")))
+                "here")
+             "."))))))
+
+(define* (rss-feed builds #:key base-url params)
+  (let ((specification (and params
+                            (assq-ref params 'specification))))
+    `(rss (@ (version "2.0"))
+          (channel
+           (title "GNU Guix continuous integration system build events.")
+           (description
+            ,(string-append
+              "Build events for "
+              (if specification
+                  (string-append "specification " specification ".")
+                  "all specifications.")))
+           (pubDate ,(date->rfc822-str (current-date)))
+           (link (@ (href "/")))
+           ,@(map build->rss-item builds)))))



reply via email to

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