Add (guix discovery).
* guix/discovery.scm, tests/discovery.scm: New files. * gnu/packages.scm (scheme-files, file-name->module-name) (scheme-modules, all-package-modules): Remove. (fold-packages): Rewrite in terms of 'fold-module-public-variables'. * gnu/tests.scm: Use (guix discovery). * Makefile.am (MODULES): Add guix/discovery.scm. (SCM_TESTS): Add tests/discovery.scm.
This commit is contained in:
parent
1dc0a66591
commit
cd903ef787
@ -50,6 +50,7 @@ MODULES = \
|
|||||||
guix/sets.scm \
|
guix/sets.scm \
|
||||||
guix/modules.scm \
|
guix/modules.scm \
|
||||||
guix/download.scm \
|
guix/download.scm \
|
||||||
|
guix/discovery.scm \
|
||||||
guix/git-download.scm \
|
guix/git-download.scm \
|
||||||
guix/hg-download.scm \
|
guix/hg-download.scm \
|
||||||
guix/monads.scm \
|
guix/monads.scm \
|
||||||
@ -279,6 +280,7 @@ SCM_TESTS = \
|
|||||||
tests/records.scm \
|
tests/records.scm \
|
||||||
tests/upstream.scm \
|
tests/upstream.scm \
|
||||||
tests/combinators.scm \
|
tests/combinators.scm \
|
||||||
|
tests/discovery.scm \
|
||||||
tests/utils.scm \
|
tests/utils.scm \
|
||||||
tests/build-utils.scm \
|
tests/build-utils.scm \
|
||||||
tests/packages.scm \
|
tests/packages.scm \
|
||||||
|
@ -24,12 +24,11 @@
|
|||||||
#:use-module (guix packages)
|
#:use-module (guix packages)
|
||||||
#:use-module (guix ui)
|
#:use-module (guix ui)
|
||||||
#:use-module (guix utils)
|
#:use-module (guix utils)
|
||||||
|
#:use-module (guix discovery)
|
||||||
#:use-module (guix memoization)
|
#:use-module (guix memoization)
|
||||||
#:use-module (guix combinators)
|
|
||||||
#:use-module ((guix build utils)
|
#:use-module ((guix build utils)
|
||||||
#:select ((package-name->name+version
|
#:select ((package-name->name+version
|
||||||
. hyphen-separated-name->name+version)))
|
. hyphen-separated-name->name+version)))
|
||||||
#:use-module (ice-9 ftw)
|
|
||||||
#:use-module (ice-9 vlist)
|
#:use-module (ice-9 vlist)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
@ -48,7 +47,6 @@
|
|||||||
%package-module-path
|
%package-module-path
|
||||||
|
|
||||||
fold-packages
|
fold-packages
|
||||||
scheme-modules ;XXX: for lack of a better place
|
|
||||||
|
|
||||||
find-packages-by-name
|
find-packages-by-name
|
||||||
find-best-packages-by-name
|
find-best-packages-by-name
|
||||||
@ -140,92 +138,17 @@ for system '~a'")
|
|||||||
directory))
|
directory))
|
||||||
%load-path)))
|
%load-path)))
|
||||||
|
|
||||||
(define* (scheme-files directory)
|
|
||||||
"Return the list of Scheme files found under DIRECTORY, recursively. The
|
|
||||||
returned list is sorted in alphabetical order."
|
|
||||||
|
|
||||||
;; Sort entries so that 'fold-packages' works in a deterministic fashion
|
|
||||||
;; regardless of details of the underlying file system.
|
|
||||||
(sort (file-system-fold (const #t) ; enter?
|
|
||||||
(lambda (path stat result) ; leaf
|
|
||||||
(if (string-suffix? ".scm" path)
|
|
||||||
(cons path result)
|
|
||||||
result))
|
|
||||||
(lambda (path stat result) ; down
|
|
||||||
result)
|
|
||||||
(lambda (path stat result) ; up
|
|
||||||
result)
|
|
||||||
(const #f) ; skip
|
|
||||||
(lambda (path stat errno result)
|
|
||||||
(warning (G_ "cannot access `~a': ~a~%")
|
|
||||||
path (strerror errno))
|
|
||||||
result)
|
|
||||||
'()
|
|
||||||
directory
|
|
||||||
stat)
|
|
||||||
string<?))
|
|
||||||
|
|
||||||
(define file-name->module-name
|
|
||||||
(let ((not-slash (char-set-complement (char-set #\/))))
|
|
||||||
(lambda (file)
|
|
||||||
"Return the module name (a list of symbols) corresponding to FILE."
|
|
||||||
(map string->symbol
|
|
||||||
(string-tokenize (string-drop-right file 4) not-slash)))))
|
|
||||||
|
|
||||||
(define* (scheme-modules directory #:optional sub-directory)
|
|
||||||
"Return the list of Scheme modules available under DIRECTORY.
|
|
||||||
Optionally, narrow the search to SUB-DIRECTORY."
|
|
||||||
(define prefix-len
|
|
||||||
(string-length directory))
|
|
||||||
|
|
||||||
(filter-map (lambda (file)
|
|
||||||
(let* ((file (substring file prefix-len))
|
|
||||||
(module (file-name->module-name file)))
|
|
||||||
(catch #t
|
|
||||||
(lambda ()
|
|
||||||
(resolve-interface module))
|
|
||||||
(lambda args
|
|
||||||
;; Report the error, but keep going.
|
|
||||||
(warn-about-load-error module args)
|
|
||||||
#f))))
|
|
||||||
(scheme-files (if sub-directory
|
|
||||||
(string-append directory "/" sub-directory)
|
|
||||||
directory))))
|
|
||||||
|
|
||||||
(define* (all-package-modules #:optional (path (%package-module-path)))
|
|
||||||
"Return the list of package modules found in PATH, a list of directories to
|
|
||||||
search."
|
|
||||||
(fold-right (lambda (spec result)
|
|
||||||
(match spec
|
|
||||||
((? string? directory)
|
|
||||||
(append (scheme-modules directory) result))
|
|
||||||
((directory . sub-directory)
|
|
||||||
(append (scheme-modules directory sub-directory)
|
|
||||||
result))))
|
|
||||||
'()
|
|
||||||
path))
|
|
||||||
|
|
||||||
(define (fold-packages proc init)
|
(define (fold-packages proc init)
|
||||||
"Call (PROC PACKAGE RESULT) for each available package, using INIT as
|
"Call (PROC PACKAGE RESULT) for each available package, using INIT as
|
||||||
the initial value of RESULT. It is guaranteed to never traverse the
|
the initial value of RESULT. It is guaranteed to never traverse the
|
||||||
same package twice."
|
same package twice."
|
||||||
(identity ; discard second return value
|
(fold-module-public-variables (lambda (object result)
|
||||||
(fold2 (lambda (module result seen)
|
(if (and (package? object)
|
||||||
(fold2 (lambda (var result seen)
|
(not (hidden-package? object)))
|
||||||
(if (and (package? var)
|
(proc object result)
|
||||||
(not (vhash-assq var seen))
|
result))
|
||||||
(not (hidden-package? var)))
|
|
||||||
(values (proc var result)
|
|
||||||
(vhash-consq var #t seen))
|
|
||||||
(values result seen)))
|
|
||||||
result
|
|
||||||
seen
|
|
||||||
(module-map (lambda (sym var)
|
|
||||||
(false-if-exception (variable-ref var)))
|
|
||||||
module)))
|
|
||||||
init
|
init
|
||||||
vlist-null
|
(all-modules (%package-module-path))))
|
||||||
(all-package-modules))))
|
|
||||||
|
|
||||||
(define find-packages-by-name
|
(define find-packages-by-name
|
||||||
(let ((packages (delay
|
(let ((packages (delay
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#:use-module (gnu services)
|
#:use-module (gnu services)
|
||||||
#:use-module (gnu services base)
|
#:use-module (gnu services base)
|
||||||
#:use-module (gnu services shepherd)
|
#:use-module (gnu services shepherd)
|
||||||
#:use-module ((gnu packages) #:select (scheme-modules))
|
#:use-module ((guix discovery) #:select (scheme-modules))
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (srfi srfi-9 gnu)
|
#:use-module (srfi srfi-9 gnu)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
|
131
guix/discovery.scm
Normal file
131
guix/discovery.scm
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
|
;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
|
||||||
|
;;;
|
||||||
|
;;; 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
(define-module (guix discovery)
|
||||||
|
#:use-module (guix ui)
|
||||||
|
#:use-module (guix combinators)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
|
#:use-module (ice-9 vlist)
|
||||||
|
#:use-module (ice-9 ftw)
|
||||||
|
#:export (scheme-modules
|
||||||
|
fold-modules
|
||||||
|
all-modules
|
||||||
|
fold-module-public-variables))
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;;;
|
||||||
|
;;; This module provides tools to discover Guile modules and the variables
|
||||||
|
;;; they export.
|
||||||
|
;;;
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(define* (scheme-files directory)
|
||||||
|
"Return the list of Scheme files found under DIRECTORY, recursively. The
|
||||||
|
returned list is sorted in alphabetical order."
|
||||||
|
|
||||||
|
;; Sort entries so that 'fold-packages' works in a deterministic fashion
|
||||||
|
;; regardless of details of the underlying file system.
|
||||||
|
(sort (file-system-fold (const #t) ;enter?
|
||||||
|
(lambda (path stat result) ;leaf
|
||||||
|
(if (string-suffix? ".scm" path)
|
||||||
|
(cons path result)
|
||||||
|
result))
|
||||||
|
(lambda (path stat result) ;down
|
||||||
|
result)
|
||||||
|
(lambda (path stat result) ;up
|
||||||
|
result)
|
||||||
|
(const #f) ;skip
|
||||||
|
(lambda (path stat errno result)
|
||||||
|
(unless (= ENOENT errno)
|
||||||
|
(warning (G_ "cannot access `~a': ~a~%")
|
||||||
|
path (strerror errno)))
|
||||||
|
result)
|
||||||
|
'()
|
||||||
|
directory
|
||||||
|
stat)
|
||||||
|
string<?))
|
||||||
|
|
||||||
|
(define file-name->module-name
|
||||||
|
(let ((not-slash (char-set-complement (char-set #\/))))
|
||||||
|
(lambda (file)
|
||||||
|
"Return the module name (a list of symbols) corresponding to FILE."
|
||||||
|
(map string->symbol
|
||||||
|
(string-tokenize (string-drop-right file 4) not-slash)))))
|
||||||
|
|
||||||
|
(define* (scheme-modules directory #:optional sub-directory)
|
||||||
|
"Return the list of Scheme modules available under DIRECTORY.
|
||||||
|
Optionally, narrow the search to SUB-DIRECTORY."
|
||||||
|
(define prefix-len
|
||||||
|
(string-length directory))
|
||||||
|
|
||||||
|
(filter-map (lambda (file)
|
||||||
|
(let* ((file (substring file prefix-len))
|
||||||
|
(module (file-name->module-name file)))
|
||||||
|
(catch #t
|
||||||
|
(lambda ()
|
||||||
|
(resolve-interface module))
|
||||||
|
(lambda args
|
||||||
|
;; Report the error, but keep going.
|
||||||
|
(warn-about-load-error module args)
|
||||||
|
#f))))
|
||||||
|
(scheme-files (if sub-directory
|
||||||
|
(string-append directory "/" sub-directory)
|
||||||
|
directory))))
|
||||||
|
|
||||||
|
(define (fold-modules proc init path)
|
||||||
|
"Fold over all the Scheme modules present in PATH, a list of directories.
|
||||||
|
Call (PROC MODULE RESULT) for each module that is found."
|
||||||
|
(fold (lambda (spec result)
|
||||||
|
(match spec
|
||||||
|
((? string? directory)
|
||||||
|
(fold proc result (scheme-modules directory)))
|
||||||
|
((directory . sub-directory)
|
||||||
|
(fold proc result
|
||||||
|
(scheme-modules directory sub-directory)))))
|
||||||
|
'()
|
||||||
|
path))
|
||||||
|
|
||||||
|
(define (all-modules path)
|
||||||
|
"Return the list of package modules found in PATH, a list of directories to
|
||||||
|
search. Entries in PATH can be directory names (strings) or (DIRECTORY
|
||||||
|
. SUB-DIRECTORY) pairs, in which case modules are searched for beneath
|
||||||
|
SUB-DIRECTORY."
|
||||||
|
(fold-modules cons '() path))
|
||||||
|
|
||||||
|
(define (fold-module-public-variables proc init modules)
|
||||||
|
"Call (PROC OBJECT RESULT) for each variable exported by one of MODULES,
|
||||||
|
using INIT as the initial value of RESULT. It is guaranteed to never traverse
|
||||||
|
the same object twice."
|
||||||
|
(identity ; discard second return value
|
||||||
|
(fold2 (lambda (module result seen)
|
||||||
|
(fold2 (lambda (var result seen)
|
||||||
|
(if (not (vhash-assq var seen))
|
||||||
|
(values (proc var result)
|
||||||
|
(vhash-consq var #t seen))
|
||||||
|
(values result seen)))
|
||||||
|
result
|
||||||
|
seen
|
||||||
|
(module-map (lambda (sym var)
|
||||||
|
(false-if-exception (variable-ref var)))
|
||||||
|
module)))
|
||||||
|
init
|
||||||
|
vlist-null
|
||||||
|
modules)))
|
||||||
|
|
||||||
|
;;; discovery.scm ends here
|
52
tests/discovery.scm
Normal file
52
tests/discovery.scm
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
;;; GNU Guix --- Functional package management for GNU
|
||||||
|
;;; Copyright © 2017 Ludovic Courtès <ludo@gnu.org>
|
||||||
|
;;;
|
||||||
|
;;; 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
(define-module (test-discovery)
|
||||||
|
#:use-module (guix discovery)
|
||||||
|
#:use-module (guix build-system)
|
||||||
|
#:use-module (srfi srfi-64)
|
||||||
|
#:use-module (ice-9 match))
|
||||||
|
|
||||||
|
(define %top-srcdir
|
||||||
|
(dirname (search-path %load-path "guix.scm")))
|
||||||
|
|
||||||
|
(test-begin "discovery")
|
||||||
|
|
||||||
|
(test-assert "scheme-modules"
|
||||||
|
(match (map module-name (scheme-modules %top-srcdir "guix/import"))
|
||||||
|
((('guix 'import _ ...) ..1)
|
||||||
|
#t)))
|
||||||
|
|
||||||
|
(test-assert "all-modules"
|
||||||
|
(match (map module-name
|
||||||
|
(all-modules `((,%top-srcdir . "guix/build-system"))))
|
||||||
|
((('guix 'build-system names) ..1)
|
||||||
|
names)))
|
||||||
|
|
||||||
|
(test-assert "fold-module-public-variables"
|
||||||
|
(let ((modules (all-modules `((,%top-srcdir . "guix/build-system")))))
|
||||||
|
(match (fold-module-public-variables (lambda (obj result)
|
||||||
|
(if (build-system? obj)
|
||||||
|
(cons obj result)
|
||||||
|
result))
|
||||||
|
'()
|
||||||
|
modules)
|
||||||
|
(((? build-system? bs) ..1)
|
||||||
|
bs))))
|
||||||
|
|
||||||
|
(test-end "discovery")
|
Loading…
Reference in New Issue
Block a user