aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludovic.courtes@inria.fr>2017-06-16 12:07:26 +0200
committerLudovic Courtès <ludo@gnu.org>2017-06-16 17:08:22 +0200
commitd27cc3bfaafe6b5b0831e88afb1c46311d382a0b (patch)
tree1cc92c5ece84a792e170913d5e4d73958f74027e
parentfa73c1937364872560c509f02b3d7648a5bed006 (diff)
downloadguix-d27cc3bfaafe6b5b0831e88afb1c46311d382a0b.tar
guix-d27cc3bfaafe6b5b0831e88afb1c46311d382a0b.tar.gz
discovery: Rewrite 'scheme-files' using 'scandir*'.
On a command like: guix environment --ad-hoc coreutils -- true this reduces the number of 'stat' calls from 14.1K to 9.7K on my setup (previously each getdents(2) call would be followed by one stat(2) call per entry). * guix/discovery.scm (scheme-files): Rewrite using 'scandir*'.
-rw-r--r--guix/discovery.scm50
1 files changed, 29 insertions, 21 deletions
diff --git a/guix/discovery.scm b/guix/discovery.scm
index 319ba7c872..6cf8d6d566 100644
--- a/guix/discovery.scm
+++ b/guix/discovery.scm
@@ -19,6 +19,7 @@
(define-module (guix discovery)
#:use-module (guix ui)
#:use-module (guix combinators)
+ #:use-module (guix build syscalls)
#:use-module (srfi srfi-1)
#:use-module (ice-9 match)
#:use-module (ice-9 vlist)
@@ -38,28 +39,35 @@
(define* (scheme-files directory)
"Return the list of Scheme files found under DIRECTORY, recursively. The
returned list is sorted in alphabetical order."
+ (define (entry-type name properties)
+ (match (assoc-ref properties 'type)
+ ('unknown
+ (stat:type (lstat name)))
+ ((? symbol? type)
+ type)))
- ;; 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<?))
+ ;; Use 'scandir*' so we can avoid an extra 'lstat' for each entry, as
+ ;; opposed to Guile's 'scandir' or 'file-system-fold'.
+ (fold-right (lambda (entry result)
+ (match entry
+ (("." . _)
+ result)
+ ((".." . _)
+ result)
+ ((name . properties)
+ (let ((absolute (string-append directory "/" name)))
+ (case (entry-type absolute properties)
+ ((directory)
+ (append (scheme-files absolute) result))
+ ((regular symlink)
+ ;; XXX: We don't recurse if we find a symlink.
+ (if (string-suffix? ".scm" name)
+ (cons absolute result)
+ result))
+ (else
+ result))))))
+ '()
+ (scandir* directory)))
(define file-name->module-name
(let ((not-slash (char-set-complement (char-set #\/))))