;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2019 by Amar Singh ;;; ;;; This file is part of GNU Guix. ;;; ;;; This program 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. ;;; ;;; 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 General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . (define-module (guix import golang)) (use-modules (srfi srfi-1) ;; fold (ice-9 rdelim) ;; read-string (guix import github) ;; latest-release (guix utils) ;; string-replace-substring (guix memoization) ;; memoize network operations (guix download) ;; download-to-store ((guix import utils) #:prefix utils:) ;; hash (guix packages) ;; packages ((guix licenses) #:prefix license:) ;; licenses (guix build-system) ;; build-system printer (guix build-system go) ;; go-build-system (guix store) ;; with-store ;; (gnu packages golang) ;; inherit (simple) go package (ice-9 textual-ports) ;; to parse readme.md (ice-9 popen) ;; open-input-ouput-pipe (web uri) ;; uri->string (srfi srfi-26) ;; cut ) ;;; To use, simply: ;;; 1. (load "golang.scm") ;;; 2. (define go-package (make-package go-name*)) ;;; 3. (package-sexp go-package) ;;; STATUS ;;; 1. latest-release DONE ;;; 1.b latest-commit PENDING/STALLED ;;; 2. go-name->guix-name DONE ;;; 2.b style go-github-com-user-project DONE ;;; 4. go-name->url DONE ;;; 4.b go-name->tarball DONE ;;; 5. go-name->sha256 (go-name version) DONE ;;; 6. go-name->synopsis DONE ;;; 7. go-name->description DONE ;;; 4-7.b. Memoize, network procedures DONE ;;; 6-7.b try to extract sentences. TODO ;;; 8. go-name->license TODO ;;; 9. go-name->inputs DONE ;;; 9.b. inputs alist DONE ;;; 10. package-sexp DONE ;;; 10.a origin-sexp DONE ;;; 11. Package Builds TODO (define-public go-name* "github.com/gohugoio/hugo") ;; for tests (define* (go-name->url go-name #:rest args) (if (string-contains go-name ".") (uri->string (string->uri (apply string-append "https://" go-name args))) #f)) (define (go-name->tarball go-name version) (go-name->url go-name "/archive/v" version ".tar.gz")) (define* (string-replace-substrings string substrings #:optional (replacement "-")) (if (null-list? substrings) string ((cut string-replace-substring <> (car substrings) replacement) (string-replace-substrings string (cdr substrings))))) ;;; Possible remove @@ if upstream exports the symbols (define (go-name->guix-name go-name) (string-append "go-" (string-replace-substrings go-name '("." "/") "-"))) ;;; Slow; accesses the network; memoized (define latest-release (memoize (lambda (go-name) ((@@ (guix import github) latest-released-version) (go-name->url go-name) (go-name->guix-name go-name))))) ;;; Slow; downloads the url from network; memoized (define url->store (@@ (guix import cran) download)) ;;; Slow; download src tarball from network, returns base32 nix-hash; ;;; memoized (define (go-name->sha256 go-name version) (utils:guix-hash-url (url->store (go-name->tarball go-name version)))) ;;; Slow; network access; memoized (define go-name->readme-string (memoize (lambda (go-name) (define (go-name->readme go-name) (go-name->url "raw.githubusercontent.com" ;; TODO, detect the domain (substring go-name (string-length "github.com")) "/master/" "README.md")) (call-with-input-file (url->store (go-name->readme go-name)) read-string)))) ;;; TODO: try to match the first sentence. (define (go-name->synopsis go-name) (substring (go-name->readme-string go-name) 0 100)) ;;; TODO: try to match the the next two sentences. (define (go-name->description go-name) (substring (go-name->readme-string go-name) 100 300)) (define shell-command (lambda* (command #:rest args) (let* ((cmd (string-join (cons command (delete #f (delete '() args))) " ")) (port (open-input-output-pipe cmd)) (result (read-string port)) (exit-code (close-pipe port))) (and (zero? exit-code) (string-split (string-trim-right result) #\newline))))) (define go-name->inputs (lambda (go-name) (let ((recursive-depends "-f '{{ join .Deps \"\\n\" }}'") (direct-depends "-f '{{ join .Imports \"\\n\" }}'") (go-command (car (shell-command "which go")))) (shell-command go-command "list" direct-depends go-name)))) ;;; License (define (string->license license-string) ((@@ (guix import cran) string->license) (string-upcase license-string))) ;;; For inputs (define format-inputs (@@ (guix import cran) format-inputs)) (define-public (make-go-package go-name) ;; Do the expensive operations only once; query network for latest ;; version (let* ((version (latest-release go-name)) (sha256 (go-name->sha256 go-name version)) (readme-string (go-name->readme-string go-name))) (package ;; (inherit go-github-com-alsm-ioprogress) (name (string-append "go-" go-name)) (version version) (source (origin (method url-fetch) (uri (go-name->tarball go-name version)) (sha256 (base32 sha256)))) (home-page (go-name->url go-name)) (build-system go-build-system) (arguments `(#:import-path ,go-name)) ;; TODO: make inputs into (unquote ..) form (inputs (format-inputs (map go-name->guix-name (go-name->inputs go-name)))) (synopsis (go-name->synopsis go-name)) (description (go-name->description go-name)) ;; TODO: license (license license:expat) ))) (define (filter-newlines string) (string-filter (lambda (x) (not (equal? x #\newline))) string)) (define bv->nix-base32 (@@ (guix packages) bytevector->nix-base32-string)) (define (origin-sexp origin) `(origin (method url-fetch) (uri ,(origin-uri origin)) (sha256 (base32 ,(bv->nix-base32 (origin-sha256 origin)))) (file-name ,(origin-file-name origin)) (patches ,(origin-patches origin)) (snippet ,(origin-snippet origin)) (patch-flags ,(origin-patch-flags origin)) (patch-inputs ,(origin-patch-inputs origin)) (modules ,(origin-modules origin)) (patch-guile ,(origin-patch-guile origin)))) (define (build-system-sexp build-system) (symbol-append (build-system-name build-system) '-build-system)) (define-public (package-sexp package) `(package (name ,(package-name package)) (version ,(package-version package)) (source ,(origin-sexp (package-source package))) (home-page ,(package-home-page package)) (build-system ,(build-system-sexp (package-build-system package))) (arguments ,(package-arguments package)) (synopsis ,(filter-newlines (package-synopsis package))) (description ,(filter-newlines (package-description package))) (inputs ,(format-inputs (map car (package-inputs package)))) (native-inputs ,(format-inputs (map car (package-native-inputs package)))) (propagated-inputs ,(format-inputs (map car (package-propagated-inputs package)))))) ;;; golang.scm ends here