;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2023 Nicolas Graves ;;; ;;; This file is part of GNU Guix. ;;; ;;; 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 . (define-module (guix import juliahub) #:use-module (ice-9 textual-ports) #:use-module (ice-9 regex) #:use-module (ice-9 match) #:use-module (ice-9 streams) #:use-module (ice-9 string-fun) #:use-module (srfi srfi-1) #:use-module (srfi srfi-9) #:use-module (srfi srfi-11) #:use-module (guix http-client) #:use-module (guix import utils) #:use-module (guix import json) #:use-module (guix base32) #:use-module (guix packages) #:use-module (guix upstream) #:use-module (json) #:use-module ((guix licenses) #:prefix license:) #:export (juliahub->guix-package)) (define (juliahub-uri name) (let* ((url (string-append "https://docs.juliahub.com/" name "/")) (port (http-fetch url #:text? #t)) (_ (get-line port)) (meta (get-line port)) (regex "url=[a-zA-Z0-9]{5}\\/[0-9\\.]*") (redirect (match:substring (string-match regex meta)))) (close-port port) (string-drop redirect 4))) (define (juliahub-url name) (let* ((url (string-append "https://docs.juliahub.com/" name "/")) (uri (juliahub-uri name))) (string-append url uri "/"))) (define (juliahub-slug-version name) (let* ((uri (juliahub-uri name)) (slug (string-take uri 5)) (latest-version (string-drop uri 6))) `(,slug ,latest-version))) (define (json->juliahub-direct-dependencies vector) (if (vector? vector) (filter-map (lambda (el) (let ((dep (json->juliahub-dependency el))) (if (juliahub-dependency-direct? dep) dep #f))) (vector->list vector)))) (define (ini-list->extra-dependencies lst) (match lst (('(extras) ooo ...) (extra-list->extra-dependencies ooo)) (((tag) ooo ...) (ini-list->extra-dependencies ooo)) ((attribute '= value ooo ...) (ini-list->extra-dependencies ooo)) ('() '()))) (define (extra-list->extra-dependencies lst) (match lst ((attribute '= value ooo ...) `(,(symbol->string attribute) ,@(extra-list->extra-dependencies ooo))) (((tag) ooo ...) '()) ('() '()))) (define (parse-extra-dependencies directory) (let* ((port (open-input-file (string-append directory "/Project.toml"))) (ini-list (stream->list (port->stream port read)))) (close-port port) (ini-list->extra-dependencies ini-list))) ;; Julia package. (define-json-mapping make-juliahub-package juliahub-package? json->juliahub-package (homepage juliahub-package-homepage) ;string (readme juliahub-package-readme) ;string (version juliahub-package-version) ;string (description juliahub-package-description) ;string (direct-dependencies juliahub-package-direct-dependencies "deps" json->juliahub-direct-dependencies) ;list of (url juliahub-package-url) ;string (uuid juliahub-package-uuid) ;string (license juliahub-package-license)) ;string (define-json-mapping make-juliahub-dependency juliahub-dependency? json->juliahub-dependency (direct? juliahub-dependency-direct? "direct") ;boolean (name juliahub-dependency-name) ;string (uuid juliahub-dependency-uuid) ;string (versions juliahub-dependency-versions "versions" vector->list)) ;list of strings (define (julia-name->guix-name name) (string-append "julia-" (snake-case name))) (define* (juliahub-fetch name #:key (version #f)) "Return a record for package NAME, or #f on failure." (and=> (json-fetch (string-append (juliahub-url name) "pkg.json")) json->juliahub-package)) (define (make-julia-sexp name source home-page synopsis description direct-dependencies test-dependencies-names licenses) "Return the `package' s-expression for a Julia package with the given NAME, VERSION, URI, HASH, HOME-PAGE, DESCRIPTION, DEPENDENCIES, TEST-DEPENDENCIES-NAMES and LICENSES." `(package (name ,(julia-name->guix-name name)) (version ,version) (source ,source) (build-system julia-build-system) ,@(if (null? direct-dependencies) '() `((propagated-inputs (list ,@(map (compose julia-name->guix-name juliahub-dependency-name) direct-dependencies))))) ,@(if (null? test-dependencies-names) '() `((native-inputs (list ,@(map julia-name->guix-name test-dependencies-names))))) (synopsis ,synopsis) (description ,description) (home-page ,home-page) (license ,(match licenses (() #f) ((license) (license->symbol license)) (_ `(list ,@(map license->symbol licenses))))))) (define* (juliahub->guix-package package-name #:key version #:allow-other-keys) "Fetch the metadata for PACKAGE-NAME from juliahub.org, and return the `package' s-expression corresponding to that package, or #f on failure. Optionally include a VERSION string to fetch a specific version juliahub." (let ((package (if version (juliahub-fetch package-name version) (juliahub-fetch package-name)))) (if package (let-values (((source directory) (git->origin+dir (juliahub-package-url package) `(tag-or-commit . ,(string-append "v" (juliahub-package-version package)))))) (let* ((dependencies-names (map juliahub-dependency-name (juliahub-package-direct-dependencies package))) (licenses (map spdx-string->license (list (juliahub-package-license package)))) (test-dependencies-names (parse-extra-dependencies directory))) (values (make-julia-sexp package-name source (juliahub-package-homepage package) (juliahub-package-description package) (beautify-description (juliahub-package-readme package)) (juliahub-package-direct-dependencies package) test-dependencies-names licenses) (append dependencies-names test-dependencies)))) (values #f '())))) (define* (import-release package #:key (version #f)) "Return an for the latest release of PACKAGE." (let* ((package-name (guix-package->juliahub-name package)) (package (juliahub-fetch package-name)) (version (or version (juliahub-version gem))) (url (rubyjuliahubs-uri gem-name version))) (upstream-source (package (package-name package)) (version version) (urls (list url))))) (define %juliahub-updater (upstream-updater (name 'juliahub) (description "Updater for Juliahub packages") (pred juliahub-package?) (import import-release))) (define* (juliahub-recursive-import package-name #:optional version) (recursive-import package-name #:repo '() #:repo->guix-package juliahub->guix-package #:guix-name ruby-package-name #:version version))