;;; Guix QA Frontpage ;;; ;;; Copyright © 2022 Christopher Baines ;;; ;;; This program is free software: you can redistribute it and/or ;;; modify it under the terms of the GNU Affero General Public License ;;; as published by the Free Software Foundation, either version 3 of ;;; the License, or (at your option) any later version. ;;; ;;; This program 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 ;;; Affero General Public License for more details. ;;; ;;; You should have received a copy of the GNU Affero General Public ;;; License along with this program. If not, see ;;; . (define-module (guix-qa-frontpage server) #:use-module (srfi srfi-1) #:use-module (srfi srfi-11) #:use-module (srfi srfi-71) #:use-module (ice-9 match) #:use-module (web http) #:use-module (web request) #:use-module (web uri) #:use-module (system repl error-handling) #:use-module (fibers web server) #:use-module (guix store) #:use-module (guix-data-service web util) #:use-module (guix-qa-frontpage database) #:use-module (guix-qa-frontpage patchwork) #:use-module (guix-qa-frontpage manage-builds) #:use-module (guix-qa-frontpage guix-data-service) #:use-module (guix-qa-frontpage view util) #:use-module (guix-qa-frontpage view home) #:use-module (guix-qa-frontpage view patches) #:use-module (guix-qa-frontpage view branches) #:use-module (guix-qa-frontpage view branch) #:use-module (guix-qa-frontpage view issue) #:export (start-guix-qa-frontpage-web-server)) (define (make-controller assets-directory database) (define handle-static-assets (if (string-prefix? (%store-prefix) assets-directory) (static-asset-from-store-renderer assets-directory) (static-asset-from-directory-renderer assets-directory))) (lambda (request method-and-path-components mime-types body) (define path (uri-path (request-uri request))) (match method-and-path-components (('GET) (render-html #:sxml (home))) (('GET "assets" rest ...) (or (handle-static-assets (string-join rest "/") (request-headers request)) (not-found (request-uri request)))) (('GET "branches") (let ((branches (with-sqlite-cache database 'branches (lambda () (list-branches (list-branches-url 2))) #:ttl 60))) (render-html #:sxml (branches-view branches)))) (('GET "branch" branch) (let ((derivation-changes change-details (with-sqlite-cache database 'branch-derivation-changes branch-derivation-changes #:args (list (branch-derivation-changes-url branch #:systems %systems-to-submit-builds-for)) #:ttl 6000))) (render-html #:sxml (branch-view branch derivation-changes)))) (('GET "patches") (let ((latest-series (with-sqlite-cache database 'latest-patchwork-series-by-issue latest-patchwork-series-by-issue #:ttl 1200))) (render-html #:sxml (patches-view latest-series)))) (('GET "issue" number) (let ((series (assq-ref (with-sqlite-cache database 'latest-patchwork-series-by-issue latest-patchwork-series-by-issue #:ttl 1200) (string->number number)))) (if series (let ((derivation-changes change-details (with-sqlite-cache database 'derivation-changes patch-series-derivation-changes #:args (list (patch-series-derivation-changes-url series #:systems %systems-to-submit-builds-for)) #:ttl 6000)) (comparison-details (with-sqlite-cache database 'lint-warnings patch-series-comparison #:args (list (patch-series-compare-url series)) #:ttl 6000))) (render-html #:sxml (issue-view number series derivation-changes change-details comparison-details))) (render-html #:sxml (general-not-found "Issue not found" "This could mean the issue does not exist, it has no patches or has been closed.") #:code 404)))) ((method path ...) (render-html #:sxml (general-not-found "Page not found" "") #:code 404))))) (define (handler request body controller) (display (format #f "~a ~a\n" (request-method request) (uri-path (request-uri request)))) (call-with-error-handling (lambda () (let-values (((request-components mime-types) (request->path-components-and-mime-type request))) (controller request (cons (request-method request) request-components) mime-types body))) #:on-error 'backtrace #:post-error (lambda args (render-html #:sxml (error-page args) #:code 500)))) (define* (start-guix-qa-frontpage-web-server port host assets-directory database) (define controller (make-controller assets-directory database)) (call-with-error-handling (lambda () (run-server (lambda (request body) (apply values (handler request body controller))) #:host host #:port port)) #:on-error 'backtrace #:post-error (lambda (key . args) (when (eq? key 'system-error) (match args (("bind" "~A" ("Address already in use") _) (simple-format (current-error-port) "\n error: guix-data-service could not start, as it could not bind to port ~A Check if it's already running, or whether another process is using that port. Also, the port used can be changed by passing the --port option.\n" port)))))))