(defpackage org.lispbuilds.nix/database/sqlite (:use :cl) (:import-from :str) (:import-from :sqlite) (:import-from :alexandria :read-file-into-string) (:import-from :arrow-macros :->>) (:import-from :org.lispbuilds.nix/util :replace-regexes) (:import-from :org.lispbuilds.nix/nix :nix-eval :system-master :nixify-symbol :make-pname :*nix-attrs-depth*) (:import-from :org.lispbuilds.nix/api :database->nix-expression) (:export :sqlite-database :init-db) (:local-nicknames (:json :com.inuoe.jzon))) (in-package org.lispbuilds.nix/database/sqlite) (defclass sqlite-database () ((url :initarg :url :reader database-url :initform (error "url required")) (init-file :initarg :init-file :reader init-file :initform (error "init file required")))) (defun init-db (db init-file) (let ((statements (->> (read-file-into-string init-file) (replace-regexes '(".*--.*") '("")) (substitute #\Space #\Newline) (str:collapse-whitespaces) (str:split #\;) (mapcar #'str:trim) (remove-if #'str:emptyp)))) (sqlite:with-transaction db (dolist (s statements) (sqlite:execute-non-query db s))))) ;; Writing Nix (defparameter prelude " # This file was auto-generated by nix-quicklisp.lisp { runCommand, fetchzip, pkgs, ... }: # Ensures that every non-slashy `system` exists in a unique .asd file. # (Think cl-async-base being declared in cl-async.asd upstream) # # This is required because we're building and loading a system called # `system`, not `asd`, so otherwise `system` would not be loadable # without building and loading `asd` first. # let createAsd = { url, sha256, asd, system }: let src = fetchzip { inherit url sha256; }; in runCommand \"source\" {} '' mkdir -pv $out cp -r ${src}/* $out find $out -name \"${asd}.asd\" | while read f; do mv -fv $f $(dirname $f)/${system}.asd || true; done ''; getAttr = builtins.getAttr; in {") ;; Random compilation errors (defparameter +broken-packages+ (list ;; no dispatch function defined for #\t "hu.dwim.logger" "hu.dwim.serializer" "hu.dwim.quasi-quote" ;; Tries to write in $HOME "ubiquitous" "math" ;; Upstream bad packaging, multiple systems in clml.blas.asd "clml.blas.hompack" ;; Fails on SBCL due to heap exhaustion "magicl" ;; Probably missing dependency in QL data "mcclim-bezier" ;; Missing dependency on c2ffi cffi extension "hu.dwim.zlib" ;; Missing libgvc.so native library "hu.dwim.graphviz" ;; These require libRmath.so, but I don't know where to get it from "cl-random" "cl-random-tests" )) (defmethod database->nix-expression ((database sqlite-database) outfile) (sqlite:with-open-database (db (database-url database)) (with-open-file (f outfile :direction :output :if-exists :supersede) ;; Fix known problematic packages before dumping the nix file. (sqlite:execute-non-query db "create temp table fixed_systems as select * from system_view") (sqlite:execute-non-query db "alter table fixed_systems add column systems") (sqlite:execute-non-query db "update fixed_systems set systems = json_array(name)") (sqlite:execute-non-query db "alter table fixed_systems add column asds") (sqlite:execute-non-query db "update fixed_systems set asds = json_array(name)") (format f prelude) (dolist (p (sqlite:execute-to-list db "select * from fixed_systems")) (destructuring-bind (name version asd url sha256 deps systems asds) p (format f "~% ") (let ((*nix-attrs-depth* 1)) (format f "~a = ~a;" (nix-eval `(:symbol ,name)) (nix-eval `(:attrs ("pname" (:string ,(make-pname name))) ("version" (:string ,version)) ("asds" (:list ,@(mapcar (lambda (asd) `(:string ,(system-master asd))) (coerce (json:parse asds) 'list)))) ("src" (:funcall "createAsd" (:attrs ("url" (:string ,url)) ("sha256" (:string ,sha256)) ("system" (:string ,(system-master name))) ("asd" (:string ,asd))))) ("systems" (:list ,@(mapcar (lambda (sys) `(:string ,sys)) (coerce (json:parse systems) 'list)))) ("lispLibs" (:list ,@(mapcar (lambda (dep) `(:funcall "getAttr" (:string ,(nixify-symbol dep)) (:symbol "pkgs"))) (remove "asdf" (str:split-omit-nulls #\, deps) :test #'string=)))) ,@(when (or (find #\/ name) (find name +broken-packages+ :test #'string=)) '(("meta" (:attrs ("broken" (:symbol "true")))))))))))) (format f "~%}~%"))))