summaryrefslogtreecommitdiff
path: root/guix/build
diff options
context:
space:
mode:
Diffstat (limited to 'guix/build')
-rw-r--r--guix/build/download.scm27
-rw-r--r--guix/build/profiles.scm149
-rw-r--r--guix/build/syscalls.scm32
3 files changed, 204 insertions, 4 deletions
diff --git a/guix/build/download.scm b/guix/build/download.scm
index 2e0b019d38..65d18eb839 100644
--- a/guix/build/download.scm
+++ b/guix/build/download.scm
@@ -19,7 +19,7 @@
(define-module (guix build download)
#:use-module (web uri)
- #:use-module (web client)
+ #:use-module ((web client) #:hide (open-socket-for-uri))
#:use-module (web response)
#:use-module (guix ftp-client)
#:use-module (guix build utils)
@@ -30,7 +30,8 @@
#:use-module (srfi srfi-26)
#:use-module (ice-9 match)
#:use-module (ice-9 format)
- #:export (open-connection-for-uri
+ #:export (open-socket-for-uri
+ open-connection-for-uri
resolve-uri-reference
maybe-expand-mirrors
url-fetch
@@ -195,6 +196,25 @@ host name without trailing dot."
(add-weak-reference record port)
record)))
+(define (open-socket-for-uri uri)
+ "Return an open port for URI. This variant works around
+<http://bugs.gnu.org/15368> which affects Guile's 'open-socket-for-uri' up to
+2.0.11 included."
+ (define rmem-max
+ ;; The maximum size for a receive buffer on Linux, see socket(7).
+ "/proc/sys/net/core/rmem_max")
+
+ (define buffer-size
+ (if (file-exists? rmem-max)
+ (call-with-input-file rmem-max read)
+ 126976)) ;the default for Linux, per 'rmem_default'
+
+ (let ((s ((@ (web client) open-socket-for-uri) uri)))
+ ;; Work around <http://bugs.gnu.org/15368> by restoring a decent
+ ;; buffer size.
+ (setsockopt s SOL_SOCKET SO_RCVBUF buffer-size)
+ s))
+
(define (open-connection-for-uri uri)
"Like 'open-socket-for-uri', but also handle HTTPS connections."
(define https?
@@ -218,6 +238,9 @@ host name without trailing dot."
(thunk)))))))
(with-https-proxy
(let ((s (open-socket-for-uri uri)))
+ ;; Buffer input and output on this port.
+ (setvbuf s _IOFBF %http-receive-buffer-size)
+
(if https?
(tls-wrap s (uri-host uri))
s)))))
diff --git a/guix/build/profiles.scm b/guix/build/profiles.scm
new file mode 100644
index 0000000000..6e316d5d2c
--- /dev/null
+++ b/guix/build/profiles.scm
@@ -0,0 +1,149 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 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 build profiles)
+ #:use-module (guix build union)
+ #:use-module (guix build utils)
+ #:use-module (guix search-paths)
+ #:use-module (srfi srfi-26)
+ #:use-module (ice-9 ftw)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 pretty-print)
+ #:export (ensure-writable-directory
+ build-profile))
+
+;;; Commentary:
+;;;
+;;; Build a user profile (essentially the union of all the installed packages)
+;;; with its associated meta-data.
+;;;
+;;; Code:
+
+(define (abstract-profile profile)
+ "Return a procedure that replaces PROFILE in VALUE with a reference to the
+'GUIX_PROFILE' environment variable. This allows users to specify what the
+user-friendly name of the profile is, for instance ~/.guix-profile rather than
+/gnu/store/...-profile."
+ (let ((replacement (string-append "${GUIX_PROFILE:-" profile "}")))
+ (match-lambda
+ ((search-path . value)
+ (let* ((separator (search-path-specification-separator search-path))
+ (items (string-tokenize* value separator))
+ (crop (cute string-drop <> (string-length profile))))
+ (cons search-path
+ (string-join (map (lambda (str)
+ (string-append replacement (crop str)))
+ items)
+ separator)))))))
+
+(define (write-environment-variable-definition port)
+ "Write the given environment variable definition to PORT."
+ (match-lambda
+ ((search-path . value)
+ (display (search-path-definition search-path value #:kind 'prefix)
+ port)
+ (newline port))))
+
+(define (build-etc/profile output search-paths)
+ "Build the 'OUTPUT/etc/profile' shell file containing environment variable
+definitions for all the SEARCH-PATHS."
+ (mkdir-p (string-append output "/etc"))
+ (call-with-output-file (string-append output "/etc/profile")
+ (lambda (port)
+ ;; The use of $GUIX_PROFILE described below is not great. Another
+ ;; option would have been to use "$1" and have users run:
+ ;;
+ ;; source ~/.guix-profile/etc/profile ~/.guix-profile
+ ;;
+ ;; However, when 'source' is used with no arguments, $1 refers to the
+ ;; first positional parameter of the calling scripts, so we can rely on
+ ;; it.
+ (display "\
+# Source this file to define all the relevant environment variables in Bash
+# for this profile. You may want to define the 'GUIX_PROFILE' environment
+# variable to point to the \"visible\" name of the profile, like this:
+#
+# GUIX_PROFILE=/path/to/profile
+# source /path/to/profile/etc/profile
+#
+# When GUIX_PROFILE is undefined, the various environment variables refer
+# to this specific profile generation.
+\n" port)
+ (let ((variables (evaluate-search-paths (cons $PATH search-paths)
+ (list output))))
+ (for-each (write-environment-variable-definition port)
+ (map (abstract-profile output) variables))))))
+
+(define (ensure-writable-directory directory)
+ "Ensure DIRECTORY exists and is writable. If DIRECTORY is currently a
+symlink (to a read-only directory in the store), then delete the symlink and
+instead make DIRECTORY a \"real\" directory containing symlinks."
+ (define (unsymlink link)
+ (let* ((target (readlink link))
+ ;; TARGET might itself be a symlink, so append "/" to make sure
+ ;; 'scandir' enters it.
+ (files (scandir (string-append target "/")
+ (negate (cut member <> '("." ".."))))))
+ (delete-file link)
+ (mkdir link)
+ (for-each (lambda (file)
+ (symlink (string-append target "/" file)
+ (string-append link "/" file)))
+ files)))
+
+ (catch 'system-error
+ (lambda ()
+ (mkdir directory))
+ (lambda args
+ (let ((errno (system-error-errno args)))
+ (if (= errno EEXIST)
+ (let ((stat (lstat directory)))
+ (case (stat:type stat)
+ ((symlink)
+ ;; "Unsymlink" DIRECTORY so that it is writable.
+ (unsymlink directory))
+ ((directory)
+ #t)
+ (else
+ (error "cannot mkdir because a same-named file exists"
+ directory))))
+ (apply throw args))))))
+
+(define* (build-profile output inputs
+ #:key manifest search-paths)
+ "Build a user profile from INPUTS in directory OUTPUT. Write MANIFEST, an
+sexp, to OUTPUT/manifest. Create OUTPUT/etc/profile with Bash definitions for
+-all the variables listed in SEARCH-PATHS."
+ ;; Make the symlinks.
+ (union-build output inputs
+ #:log-port (%make-void-port "w"))
+
+ ;; Store meta-data.
+ (call-with-output-file (string-append output "/manifest")
+ (lambda (p)
+ (pretty-print manifest p)))
+
+ ;; Make sure we can write to 'OUTPUT/etc'. 'union-build' above could have
+ ;; made 'etc' a symlink to a read-only sub-directory in the store so we need
+ ;; to work around that.
+ (ensure-writable-directory (string-append output "/etc"))
+
+ ;; Write 'OUTPUT/etc/profile'.
+ (build-etc/profile output search-paths))
+
+;;; profile.scm ends here
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index b62a8cce64..3585bf27a8 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2014 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -29,6 +29,7 @@
MS_REMOUNT
MS_BIND
MS_MOVE
+ restart-on-EINTR
mount
umount
mount-points
@@ -46,6 +47,7 @@
network-interface-address
set-network-interface-flags
set-network-interface-address
+ set-network-interface-up
configure-network-interface))
;;; Commentary:
@@ -88,6 +90,19 @@
(ref bv))))
(lambda () 0)))
+(define (call-with-restart-on-EINTR thunk)
+ (let loop ()
+ (catch 'system-error
+ thunk
+ (lambda args
+ (if (= (system-error-errno args) EINTR)
+ (loop)
+ (apply throw args))))))
+
+(define-syntax-rule (restart-on-EINTR expr)
+ "Evaluate EXPR and restart upon EINTR. Return the value of EXPR."
+ (call-with-restart-on-EINTR (lambda () expr)))
+
(define (augment-mtab source target type options)
"Augment /etc/mtab with information about the given mount point."
(let ((port (open-file "/etc/mtab" "a")))
@@ -203,7 +218,7 @@ constants from <sys/mount.h>."
(let ((ret (proc (string->pointer device)))
(err (errno)))
(unless (zero? ret)
- (throw 'system-error "swapff" "~S: ~A"
+ (throw 'system-error "swapoff" "~S: ~A"
(list device (strerror err))
(list err)))))))
@@ -552,4 +567,17 @@ the same type as that returned by 'make-socket-address'."
(lambda ()
(close-port sock)))))
+(define* (set-network-interface-up name
+ #:key (family AF_INET))
+ "Turn up the interface NAME."
+ (let ((sock (socket family SOCK_STREAM 0)))
+ (dynamic-wind
+ (const #t)
+ (lambda ()
+ (let ((flags (network-interface-flags sock name)))
+ (set-network-interface-flags sock name
+ (logior flags IFF_UP))))
+ (lambda ()
+ (close-port sock)))))
+
;;; syscalls.scm ends here