;;; Guix Build Coordinator ;;; ;;; Copyright © 2020 Christopher Baines ;;; ;;; This file is part of the guix-build-coordinator. ;;; ;;; The Guix Build Coordinator 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. ;;; ;;; The Guix Build Coordinator 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 the guix-data-service. If not, see ;;; . (define-module (guix-build-coordinator guix-data-service) #:use-module (srfi srfi-1) #:use-module (srfi srfi-11) #:use-module (srfi srfi-71) #:use-module (ice-9 exceptions) #:use-module (rnrs bytevectors) #:use-module (json) #:use-module (web client) #:use-module (web response) #:use-module (guix-build-coordinator utils) #:use-module (guix-build-coordinator datastore) #:export (send-build-event-to-guix-data-service send-events-for-all-builds send-events-for-selected-builds)) (define (send-build-event-to-guix-data-service target-url event) (send-build-events-to-guix-data-service target-url (list event))) (define (send-build-events-to-guix-data-service target-url events) (define body (scm->json-string `((items . ,(list->vector events))))) (let* ((response body (with-port-timeouts (lambda () (http-post target-url #:body body ;; Guile doesn't treat JSON as text, so decode the ;; body manually #:decode-body? #f)))) (code (response-code response))) (unless (and (>= code 200) (< code 300)) (raise-exception (make-exception-with-message (simple-format #f "code: ~A response: ~A" code (utf8->string body))))))) (define (events-for-build datastore build-details) (define build-id (assq-ref build-details 'uuid)) (define derivation-name (assq-ref build-details 'derivation-name)) `(((type . build) (event . scheduled) (build_id . ,build-id) (derivation . ,derivation-name) ,@(or (and=> (datastore-find-derivation-output-details datastore (assq-ref build-details 'derivation-name)) (lambda (output-details) `((derivation_outputs . ,(list->vector (map (lambda (output-details) `((output . ,(assq-ref output-details 'output)) (name . ,(assq-ref output-details 'name)) ,@(if (assq-ref output-details 'hash) `((hash_algorithm . ,(assq-ref output-details 'hash-algorithm)) (hash . ,(assq-ref output-details 'hash))) '()) (recursive . ,(assq-ref output-details 'recursive?)))) output-details)))))) '()) ,@(let ((created-at (assq-ref build-details 'created-at))) (if created-at `((timestamp . ,(string->number (strftime "%s" (assq-ref build-details 'created-at))))) '()))) ,@(map (lambda (start-time-and-agent) `((type . build) (event . started) (build_id . ,build-id) (derivation . ,derivation-name) (timestamp . ,(string->number (strftime "%s" (assq-ref start-time-and-agent 'start-time)))))) (reverse (datastore-find-build-starts datastore build-id))) ,@(let ((result-details (datastore-find-build-result datastore build-id))) (if result-details `(((type . build) (event . ,(let ((result (assq-ref result-details 'result))) (cond ((string=? result "success") 'succeeded) ((string=? result "failure") 'failed) (else (error "unknown result"))))) (build_id . ,build-id) (derivation . ,derivation-name) ,@(let ((end-time (assq-ref build-details 'end-time))) (if end-time `((timestamp . ,(string->number (strftime "%s" (assq-ref build-details 'end-time))))) '())))) '())))) (define (send-events-for-all-builds datastore target-url) (datastore-for-each-build datastore (lambda (build-id) (simple-format #t "~A\n" build-id) (let ((events (events-for-build datastore (datastore-find-build datastore build-id)))) (send-build-events-to-guix-data-service target-url events))))) (define (send-events-for-selected-builds datastore target-url . criteria) (let ((all-build-details (apply datastore-fold-builds datastore cons '() criteria))) (fold (lambda (build-details result) (simple-format #t "~A\n" (assq-ref build-details 'uuid)) (let ((events (events-for-build datastore build-details))) (send-build-events-to-guix-data-service target-url events)) (+ 1 result)) 0 all-build-details)))