summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Courtès <ludo@gnu.org>2013-01-09 22:09:58 +0100
committerLudovic Courtès <ludo@gnu.org>2013-01-09 22:10:06 +0100
commitb2d58cd80a04ccab09a947d187ae55ff199eae08 (patch)
tree0fc47cbad22bb432f4eee5db386e5bacbab52ca1
parentb9e5c0a949fa627da55ea53fd71dfa96ad8a2b4b (diff)
union: Detect collisions, and delete duplicate leaves.
* guix/build/union.scm (delete-duplicate-leaves): New procedure. (union-build)[leaf=?, resolve-collision]: New procedures. Use `delete-duplicate-leaves' on the result of `tree-union'. * tests/union.scm ("delete-duplicate-leaves, default", "delete-duplicate-leaves, file names"): New tests.
-rw-r--r--guix/build/union.scm66
-rw-r--r--tests/union.scm21
2 files changed, 83 insertions, 4 deletions
diff --git a/guix/build/union.scm b/guix/build/union.scm
index ffd367917ae..d1578a6ef53 100644
--- a/guix/build/union.scm
+++ b/guix/build/union.scm
@@ -1,5 +1,5 @@
1;;; Guix --- Nix package management from Guile. -*- coding: utf-8 -*- 1;;; Guix --- Nix package management from Guile. -*- coding: utf-8 -*-
2;;; Copyright (C) 2012 Ludovic Courtès <ludo@gnu.org> 2;;; Copyright (C) 2012, 2013 Ludovic Courtès <ludo@gnu.org>
3;;; 3;;;
4;;; This file is part of Guix. 4;;; This file is part of Guix.
5;;; 5;;;
@@ -19,9 +19,11 @@
19(define-module (guix build union) 19(define-module (guix build union)
20 #:use-module (ice-9 ftw) 20 #:use-module (ice-9 ftw)
21 #:use-module (ice-9 match) 21 #:use-module (ice-9 match)
22 #:use-module (ice-9 format)
22 #:use-module (srfi srfi-1) 23 #:use-module (srfi srfi-1)
23 #:use-module (srfi srfi-26) 24 #:use-module (srfi srfi-26)
24 #:export (tree-union 25 #:export (tree-union
26 delete-duplicate-leaves
25 union-build)) 27 union-build))
26 28
27;;; Commentary: 29;;; Commentary:
@@ -56,6 +58,48 @@ itself a tree. "
56 '() 58 '()
57 (delete-duplicates (map car dirs))))))))) 59 (delete-duplicates (map car dirs)))))))))
58 60
61(define* (delete-duplicate-leaves tree
62 #:optional
63 (leaf=? equal?)
64 (delete-duplicates (match-lambda
65 ((head _ ...) head))))
66 "Delete duplicate leaves from TREE. Two leaves are considered equal
67when LEAF=? applied to them returns #t. Each collision (list of leaves
68that are LEAF=?) is passed to DELETE-DUPLICATES, which must return a
69single leaf."
70 (let loop ((tree tree))
71 (match tree
72 ((dir children ...)
73 (let ((dirs (filter pair? children))
74 (leaves (remove pair? children)))
75 (define collisions
76 (fold (lambda (leaf result)
77 (define same?
78 (cut leaf=? leaf <>))
79
80 (if (any (cut find same? <>) result)
81 result
82 (match (filter same? leaves)
83 ((_)
84 result)
85 ((collision ...)
86 (cons collision result)))))
87 '()
88 leaves))
89
90 (define non-collisions
91 (filter (lambda (leaf)
92 (match (filter (cut leaf=? leaf <>) leaves)
93 ((_) #t)
94 ((_ _ ..1) #f)))
95 leaves))
96
97 `(,dir
98 ,@non-collisions
99 ,@(map delete-duplicates collisions)
100 ,@(map loop dirs))))
101 (leaf leaf))))
102
59(define* (union-build output directories) 103(define* (union-build output directories)
60 "Build in the OUTPUT directory a symlink tree that is the union of all 104 "Build in the OUTPUT directory a symlink tree that is the union of all
61the DIRECTORIES." 105the DIRECTORIES."
@@ -88,12 +132,28 @@ the DIRECTORIES."
88 (((? string?) leaves ...) 132 (((? string?) leaves ...)
89 leaves))) 133 leaves)))
90 134
135 (define (leaf=? a b)
136 (equal? (basename a) (basename b)))
137
138 (define (resolve-collision leaves)
139 ;; LEAVES all have the same basename, so choose one of them.
140 (format (current-error-port) "warning: collision encountered: ~{~a ~}~%"
141 leaves)
142
143 ;; TODO: Implement smarter strategies.
144 (format (current-error-port) "warning: arbitrarily choosing ~a~%"
145 (car leaves))
146 (car leaves))
147
91 (setvbuf (current-output-port) _IOLBF) 148 (setvbuf (current-output-port) _IOLBF)
92 (setvbuf (current-error-port) _IOLBF) 149 (setvbuf (current-error-port) _IOLBF)
93 150
94 (mkdir output) 151 (mkdir output)
95 (let loop ((tree (tree-union (append-map (compose tree-leaves file-tree) 152 (let loop ((tree (delete-duplicate-leaves
96 directories))) 153 (tree-union (append-map (compose tree-leaves file-tree)
154 directories))
155 leaf=?
156 resolve-collision))
97 (dir '())) 157 (dir '()))
98 (match tree 158 (match tree
99 ((? string?) 159 ((? string?)
diff --git a/tests/union.scm b/tests/union.scm
index 317d49dc35e..a3859434a23 100644
--- a/tests/union.scm
+++ b/tests/union.scm
@@ -1,5 +1,5 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2012 Ludovic Courtès <ludo@gnu.org> 2;;; Copyright © 2012, 2013 Ludovic Courtès <ludo@gnu.org>
3;;; 3;;;
4;;; This file is part of GNU Guix. 4;;; This file is part of GNU Guix.
5;;; 5;;;
@@ -64,6 +64,25 @@
64 (bin make) 64 (bin make)
65 (share (doc (make README)))))) 65 (share (doc (make README))))))
66 66
67(test-equal "delete-duplicate-leaves, default"
68 '(bin make touch ls)
69 (delete-duplicate-leaves '(bin ls make touch ls)))
70
71(test-equal "delete-duplicate-leaves, file names"
72 '("doc" ("info"
73 "/binutils/ld.info"
74 "/gcc/gcc.info"
75 "/binutils/standards.info"))
76 (let ((leaf=? (lambda (a b)
77 (string=? (basename a) (basename b)))))
78 (delete-duplicate-leaves '("doc"
79 ("info"
80 "/binutils/ld.info"
81 "/binutils/standards.info"
82 "/gcc/gcc.info"
83 "/gcc/standards.info"))
84 leaf=?)))
85
67(test-skip (if (and %store 86(test-skip (if (and %store
68 (false-if-exception 87 (false-if-exception
69 (getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV))) 88 (getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)))