summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--HACKING10
-rw-r--r--Makefile.am3
-rw-r--r--build-aux/compile-all.scm33
-rw-r--r--configure.ac8
-rw-r--r--doc/guix.texi42
-rw-r--r--gnu/build/install.scm30
-rw-r--r--gnu/packages/bioinformatics.scm6
-rw-r--r--gnu/packages/bittorrent.scm4
-rw-r--r--gnu/packages/certs.scm4
-rw-r--r--gnu/packages/conky.scm4
-rw-r--r--gnu/packages/databases.scm4
-rw-r--r--gnu/packages/debug.scm12
-rw-r--r--gnu/packages/documentation.scm22
-rw-r--r--gnu/packages/games.scm6
-rw-r--r--gnu/packages/gnustep.scm65
-rw-r--r--gnu/packages/gnuzilla.scm95
-rw-r--r--gnu/packages/gtk.scm78
-rw-r--r--gnu/packages/guile.scm3
-rw-r--r--gnu/packages/linux.scm8
-rw-r--r--gnu/packages/mail.scm101
-rw-r--r--gnu/packages/messaging.scm4
-rw-r--r--gnu/packages/ocaml.scm202
-rw-r--r--gnu/packages/python.scm18
-rw-r--r--gnu/packages/shellutils.scm4
-rw-r--r--gnu/packages/version-control.scm11
-rw-r--r--gnu/packages/video.scm8
-rw-r--r--gnu/packages/w3m.scm4
-rw-r--r--guix/build/download.scm3
-rw-r--r--guix/build/syscalls.scm45
-rw-r--r--guix/scripts/pack.scm151
-rw-r--r--guix/upstream.scm4
-rw-r--r--guix/zlib.scm29
-rw-r--r--po/guix/POTFILES.in1
-rw-r--r--tests/guix-system.sh9
-rw-r--r--tests/pack.scm79
-rw-r--r--tests/store.scm4
-rw-r--r--tests/zlib.scm11
37 files changed, 869 insertions, 256 deletions
diff --git a/HACKING b/HACKING
index 1e0bddfaf4..46a7249616 100644
--- a/HACKING
+++ b/HACKING
@@ -2,7 +2,7 @@
 
 #+TITLE: Hacking GNU Guix and Its Incredible Distro
 
-Copyright © 2012, 2013, 2014, 2016 Ludovic Courtès <ludo@gnu.org>
+Copyright © 2012, 2013, 2014, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
 Copyright © 2015, 2017 Mathieu Lirzin <mthl@gnu.org>
 Copyright © 2017 Leo Famulari <leo@famulari.name>
 
@@ -25,8 +25,10 @@ convenient.  When you deem it necessary, feel free to ask for it on the
 mailing list.  When you get commit access, please make sure to follow the
 policy below (discussions of the policy can take place on guix-devel@gnu.org.)
 
-Non-trivial patches should always be posted to guix-devel@gnu.org (trivial
-patches include fixing typos, etc.)
+Non-trivial patches should always be posted to guix-patches@gnu.org (trivial
+patches include fixing typos, etc.)  This mailing list fills the
+patch-tracking database at [[https://bugs.gnu.org/guix-patches]]; see
+"Contributing" in the manual for details.
 
 For patches that just add a new package, and a simple one, it’s OK to commit,
 if you’re confident (which means you successfully built it in a chroot setup,
@@ -48,7 +50,7 @@ You can prevent yourself from accidentally pushing unsigned commits to Savannah
 by using the pre-push Git hook called 'pre-push'. It's located at
 'etc/git/pre-push'.
 
-For anything else, please post to guix-devel@gnu.org and leave time for a
+For anything else, please post to guix-patches@gnu.org and leave time for a
 review, without committing anything.  If you didn’t receive any reply
 after two weeks, and if you’re confident, it’s OK to commit.
 
diff --git a/Makefile.am b/Makefile.am
index 2443f6891f..4d7bc1caeb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -298,6 +298,7 @@ SCM_TESTS =					\
   tests/services.scm				\
   tests/scripts-build.scm			\
   tests/containers.scm				\
+  tests/pack.scm				\
   tests/import-utils.scm
 
 if HAVE_GUILE_JSON
@@ -489,7 +490,7 @@ AM_DISTCHECK_CONFIGURE_FLAGS =			\
 guix-binary.%.tar.xz:
 	$(AM_V_GEN)GUIX_PACKAGE_PATH=				\
 	tarball=`$(top_builddir)/pre-inst-env guix pack -C xz	\
-	  -s "$*" guix` ;					\
+	  -s "$*" --localstatedir guix` ;			\
 	cp "$$tarball" "$@.tmp" ; mv "$@.tmp" "$@"
 
 
diff --git a/build-aux/compile-all.scm b/build-aux/compile-all.scm
index 6ce4040887..d077d75229 100644
--- a/build-aux/compile-all.scm
+++ b/build-aux/compile-all.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2016 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
-;;; Copyright © 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2016, 2017 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -63,6 +63,34 @@
     (format #t "  LOAD     ~a~%" module)
     (resolve-interface module)))
 
+(cond-expand
+  (guile-2.2 (use-modules (language tree-il optimize)
+                          (language cps optimize)))
+  (else #f))
+
+(define %default-optimizations
+  ;; Default optimization options (equivalent to -O2 on Guile 2.2).
+  (cond-expand
+    (guile-2.2 (append (tree-il-default-optimization-options)
+                       (cps-default-optimization-options)))
+    (else '())))
+
+(define %lightweight-optimizations
+  ;; Lightweight optimizations (like -O0, but with partial evaluation).
+  (let loop ((opts %default-optimizations)
+             (result '()))
+    (match opts
+      (() (reverse result))
+      ((#:partial-eval? _ rest ...)
+       (loop rest `(#t #:partial-eval? ,@result)))
+      ((kw _ rest ...)
+       (loop rest `(#f ,kw ,@result))))))
+
+(define (optimization-options file)
+  (if (string-contains file "gnu/packages/")
+      %lightweight-optimizations                  ;build faster
+      '()))
+
 (define (compile-file* file output-mutex)
   (let ((go (scm->go file)))
     (with-mutex output-mutex
@@ -74,7 +102,8 @@
         (lambda ()
           (compile-file file
                         #:output-file go
-                        #:opts `(#:warnings ,warnings)))))))
+                        #:opts `(#:warnings ,warnings
+                                 ,@(optimization-options file))))))))
 
 ;; Install a SIGINT handler to give unwind handlers in 'compile-file' an
 ;; opportunity to run upon SIGINT and to remove temporary output files.
diff --git a/configure.ac b/configure.ac
index e5daadb121..3bf2bf1610 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,9 +73,9 @@ m4_pattern_forbid([PKG_CHECK_MODULES])
 m4_pattern_forbid([GUILE_MODULE_AVAILABLE])
 m4_pattern_forbid([^GUILE_P$])
 
-dnl Search for 'guile' and 'guild'.  Prefer 2.0 until the 2.2 upgrade is
-dnl complete.  This macro defines 'GUILE_EFFECTIVE_VERSION'.
-GUILE_PKG([2.0 2.2])
+dnl Search for 'guile' and 'guild'.  This macro defines
+dnl 'GUILE_EFFECTIVE_VERSION'.
+GUILE_PKG([2.2 2.0])
 GUILE_PROGS
 if test "x$GUILD" = "x"; then
    AC_MSG_ERROR(['guild' binary not found; please check your guile-2.x installation.])
@@ -83,8 +83,6 @@ fi
 
 if test "x$GUILE_EFFECTIVE_VERSION" = "x2.0"; then
   PKG_CHECK_MODULES([GUILE], [guile-2.0 >= 2.0.7])
-else
-  AC_MSG_WARN([Guile $GUILE_EFFECTIVE_VERSION is not fully supported!])
 fi
 
 dnl Installation directory for .scm and .go files.
diff --git a/doc/guix.texi b/doc/guix.texi
index aba207c856..0c6cb56a2b 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -535,7 +535,7 @@ make guix-binary.@var{system}.tar.xz
 ... which, in turn, runs:
 
 @example
-guix pack -s @var{system} guix
+guix pack -s @var{system} --localstatedir guix
 @end example
 
 @xref{Invoking guix pack}, for more info on this handy tool.
@@ -551,7 +551,8 @@ in the Guix source tree for additional details.
 GNU Guix depends on the following packages:
 
 @itemize
-@item @url{http://gnu.org/software/guile/, GNU Guile}, version 2.0.7 or later;
+@item @url{http://gnu.org/software/guile/, GNU Guile}, version 2.0.7 or
+later, including 2.2.x;
 @item @url{http://gnupg.org/, GNU libgcrypt};
 @item
 @uref{http://gnutls.org/, GnuTLS}, specifically its Guile bindings
@@ -2422,6 +2423,18 @@ same as would be created by @command{guix package -i}.  It is this
 mechanism that is used to create Guix's own standalone binary tarball
 (@pxref{Binary Installation}).
 
+Users of this pack would have to run
+@file{/gnu/store/@dots{}-profile/bin/guile} to run Guile, which you may
+find inconvenient.  To work around it, you can create, say, a
+@file{/opt/gnu/bin} symlink to the profile:
+
+@example
+guix pack -S /opt/gnu/bin=bin guile emacs geiser
+@end example
+
+@noindent
+That way, users can happily type @file{/opt/gnu/bin/guile} and enjoy.
+
 Several command-line options allow you to customize your pack:
 
 @table @code
@@ -2434,6 +2447,31 @@ the system type of the build host.
 @itemx -C @var{tool}
 Compress the resulting tarball using @var{tool}---one of @code{gzip},
 @code{bzip2}, @code{xz}, or @code{lzip}.
+
+@item --symlink=@var{spec}
+@itemx -S @var{spec}
+Add the symlinks specified by @var{spec} to the pack.  This option can
+appear several times.
+
+@var{spec} has the form @code{@var{source}=@var{target}}, where
+@var{source} is the symlink that will be created and @var{target} is the
+symlink target.
+
+For instance, @code{-S /opt/gnu/bin=bin} creates a @file{/opt/gnu/bin}
+symlink pointing to the @file{bin} sub-directory of the profile.
+
+@item --localstatedir
+Include the ``local state directory'', @file{/var/guix}, in the
+resulting pack.
+
+@file{/var/guix} contains the store database (@pxref{The Store}) as well
+as garbage-collector roots (@pxref{Invoking guix gc}).  Providing it in
+the pack means that the store is ``complete'' and manageable by Guix;
+not providing it pack means that the store is ``dead'': items cannot be
+added to it or removed from it after extraction of the pack.
+
+One use case for this is the Guix self-contained binary tarball
+(@pxref{Binary Installation}).
 @end table
 
 In addition, @command{guix pack} supports all the common build options
diff --git a/gnu/build/install.scm b/gnu/build/install.scm
index 5c2b35632d..5cb6055a0c 100644
--- a/gnu/build/install.scm
+++ b/gnu/build/install.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2016 Chris Marusich <cmmarusich@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -24,6 +24,7 @@
   #:use-module (ice-9 match)
   #:export (install-grub
             install-grub-config
+            evaluate-populate-directive
             populate-root-file-system
             reset-timestamps
             register-closure
@@ -192,13 +193,16 @@ rest of STORE."
 
 (define* (populate-single-profile-directory directory
                                             #:key profile closure
-                                            deduplicate?)
+                                            deduplicate?
+                                            register?)
   "Populate DIRECTORY with a store containing PROFILE, whose closure is given
 in the file called CLOSURE (as generated by #:references-graphs.)  DIRECTORY
 is initialized to contain a single profile under /root pointing to PROFILE.
-DEDUPLICATE? determines whether to deduplicate files in the store.
+When REGISTER? is true, initialize DIRECTORY/var/guix/db to reflect the
+contents of the store; DEDUPLICATE? determines whether to deduplicate files in
+the store.
 
-This is used to create the self-contained Guix tarball."
+This is used to create the self-contained tarballs with 'guix pack'."
   (define (scope file)
     (string-append directory "/" file))
 
@@ -213,14 +217,16 @@ This is used to create the self-contained Guix tarball."
 
   ;; Populate the store.
   (populate-store (list closure) directory)
-  (register-closure (canonicalize-path directory) closure
-                    #:deduplicate? deduplicate?)
-
-  ;; XXX: 'guix-register' registers profiles as GC roots but the symlink
-  ;; target uses $TMPDIR.  Fix that.
-  (delete-file (scope "/var/guix/gcroots/profiles"))
-  (symlink* "/var/guix/profiles"
-            "/var/guix/gcroots/profiles")
+
+  (when register?
+    (register-closure (canonicalize-path directory) closure
+                      #:deduplicate? deduplicate?)
+
+    ;; XXX: 'guix-register' registers profiles as GC roots but the symlink
+    ;; target uses $TMPDIR.  Fix that.
+    (delete-file (scope "/var/guix/gcroots/profiles"))
+    (symlink* "/var/guix/profiles"
+              "/var/guix/gcroots/profiles"))
 
   ;; Make root's profile, which makes it a GC root.
   (mkdir-p* %root-profile)
diff --git a/gnu/packages/bioinformatics.scm b/gnu/packages/bioinformatics.scm
index 770bea7e32..239b94b6c4 100644
--- a/gnu/packages/bioinformatics.scm
+++ b/gnu/packages/bioinformatics.scm
@@ -4284,7 +4284,8 @@ to the user's query of interest.")
          'install 'install-library
          (lambda* (#:key outputs #:allow-other-keys)
            (let ((lib (string-append (assoc-ref outputs "out") "/lib")))
-             (install-file "libbam.a" lib)))
+             (install-file "libbam.a" lib)
+             #t))
          (alist-cons-after
           'install 'install-headers
           (lambda* (#:key outputs #:allow-other-keys)
@@ -4336,7 +4337,8 @@ viewer.")
                                (assoc-ref outputs "out") "/bin")))
                      (mkdir-p bin)
                      (copy-file "samtools"
-                                (string-append bin "/samtools")))))
+                                (string-append bin "/samtools"))
+                     #t)))
                (delete 'patch-tests)
                (delete 'configure))))))))
 
diff --git a/gnu/packages/bittorrent.scm b/gnu/packages/bittorrent.scm
index 9e56f667a4..635b94f4a0 100644
--- a/gnu/packages/bittorrent.scm
+++ b/gnu/packages/bittorrent.scm
@@ -263,7 +263,7 @@ maintained upstream.")
 (define-public aria2
   (package
     (name "aria2")
-    (version "1.30.0")
+    (version "1.31.0")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://github.com/tatsuhiro-t/aria2/"
@@ -271,7 +271,7 @@ maintained upstream.")
                                   name "-" version ".tar.xz"))
               (sha256
                (base32
-                "1xiiqk4yiqr0c4hf05zkma9if13lp3wh37z1r0w60ahxs5k56v5z"))))
+                "131zh75fqw9a1j0igl8gx3lwmhhbicdmp2p387r0cd5j928631bv"))))
     (build-system gnu-build-system)
     (arguments
      `(#:configure-flags (list "--enable-libaria2"
diff --git a/gnu/packages/certs.scm b/gnu/packages/certs.scm
index 7f5c5b793f..e35e9aabab 100644
--- a/gnu/packages/certs.scm
+++ b/gnu/packages/certs.scm
@@ -74,7 +74,7 @@
 (define-public nss-certs
   (package
     (name "nss-certs")
-    (version "3.29.3")
+    (version "3.29.2")
     (source (origin
               (method url-fetch)
               (uri (let ((version-with-underscores
@@ -85,7 +85,7 @@
                       "nss-" version ".tar.gz")))
               (sha256
                (base32
-                "1sz1r2iml9bhd4iqiqz75gii855a25895vpy9scjky0y4lqwrp9m"))))
+                "149807rmzb76hnh48rw4m9jw83iw0168njzchz0hmbsgc8mk0i5w"))))
     (build-system gnu-build-system)
     (outputs '("out"))
     (native-inputs
diff --git a/gnu/packages/conky.scm b/gnu/packages/conky.scm
index 206546b53a..9c933a4bc0 100644
--- a/gnu/packages/conky.scm
+++ b/gnu/packages/conky.scm
@@ -32,7 +32,7 @@
 (define-public conky
   (package
     (name "conky")
-    (version "1.10.3")
+    (version "1.10.6")
     (source
      (origin
        (method url-fetch)
@@ -40,7 +40,7 @@
                            version ".tar.gz"))
        (file-name (string-append name "-" version ".tar.gz"))
        (sha256
-        (base32 "1m9byrmpc2sprzk44v447yaqjzsvw230a0mlw7y1ngz3m3y44qs5"))))
+        (base32 "1jk0my7z45vz9vd8958d27nkk4kvr53k7wyf6cz2x9xjc0lri02c"))))
     (build-system cmake-build-system)
     (arguments
      `(#:tests? #f ; there are no tests
diff --git a/gnu/packages/databases.scm b/gnu/packages/databases.scm
index 4b637f0c70..8b01a2f01b 100644
--- a/gnu/packages/databases.scm
+++ b/gnu/packages/databases.scm
@@ -365,7 +365,7 @@ Language.")
 (define-public mariadb
   (package
     (name "mariadb")
-    (version "10.1.21")
+    (version "10.1.22")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://downloads.mariadb.org/f/"
@@ -373,7 +373,7 @@ Language.")
                                   name "-" version ".tar.gz"))
               (sha256
                (base32
-                "144lcm5awcf0k6a7saqfr4p2kg8r5wbdhdm4cmn2m8hyg1an70as"))))
+                "1kk674mx2bf22yivvzv1al5gdg9kyxar47m282bylb6kg8p5gc5w"))))
     (build-system cmake-build-system)
     (arguments
      '(#:configure-flags
diff --git a/gnu/packages/debug.scm b/gnu/packages/debug.scm
index b7d6bbc0eb..6278f661ef 100644
--- a/gnu/packages/debug.scm
+++ b/gnu/packages/debug.scm
@@ -304,12 +304,12 @@ down the road.")
       (home-page "https://github.com/losalamos/stress-make")
       (synopsis "Expose race conditions in Makefiles")
       (description
-       "Stress Make is a customized GNU Make that explicitely managess the
-order in which concurrent jobs are run in order to provoke erroneous behavior
-into becoming manifest.  It can run jobs in the order they're launched, in
-backwards order, or in random order.  The thought is that if code builds
-correctly with Stress Make then it is likely that the @code{Makefile} contains
-no race conditions.")
+       "Stress Make is a customized GNU Make that explicitely manages the order
+in which concurrent jobs are run to provoke erroneous behavior into becoming
+manifest.  It can run jobs in the order in which they're launched, in backwards
+order, or in random order.  The thought is that if code builds correctly with
+Stress Make, then it is likely that the @code{Makefile} contains no race
+conditions.")
       ;; stress-make wrapper is under BSD-3-modifications-must-be-indicated,
       ;; and patched GNU Make is under its own license.
       (license (list (non-copyleft "COPYING.md")
diff --git a/gnu/packages/documentation.scm b/gnu/packages/documentation.scm
index cd42bc0f35..792e70ecdd 100644
--- a/gnu/packages/documentation.scm
+++ b/gnu/packages/documentation.scm
@@ -4,6 +4,7 @@
 ;;; Copyright © 2016 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2016 Roel Janssen <roel@gnu.org>
 ;;; Copyright © 2016 Thomas Danckaert <post@thomasdanckaert.be>
+;;; Copyright © 2017 Kei Kebreau <kei@openmailbox.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -55,6 +56,23 @@
      `(#:tests? #f                     ; no 'check' target
        #:phases
        (modify-phases %standard-phases
+         ;; Some XML-related binaries are required for asciidoc's proper usage.
+         ;; Without these, asciidoc fails when parsing XML documents, either
+         ;; reporting a missing "xmllint" binary or, when passed the
+         ;; "--no-xmllint" option, a missing "xsltproc" binary.
+         ;; The following phase enables asciidoc to find some of them.
+         (add-before 'configure 'set-xml-binary-paths
+                     (lambda* (#:key inputs #:allow-other-keys)
+                       (let* ((libxml2 (assoc-ref inputs "libxml2"))
+                              (xmllint (string-append libxml2 "/bin/xmllint"))
+                              (libxslt (assoc-ref inputs "libxslt"))
+                              (xsltproc (string-append libxslt "/bin/xsltproc")))
+                         (substitute* "a2x.py"
+                           (("XMLLINT = 'xmllint'")
+                            (string-append "XMLLINT = '" xmllint "'"))
+                           (("XSLTPROC = 'xsltproc'")
+                            (string-append "XSLTPROC = '" xsltproc "'")))
+                         #t)))
          ;; Make asciidoc use the local docbook-xsl package instead of fetching
          ;; it from the internet at run-time.
          (add-before 'install 'make-local-docbook-xsl
@@ -69,7 +87,9 @@ release/xsl/current")
                                           ,(package-version docbook-xsl)))))
                        #t)))))
     (inputs `(("python" ,python-2)
-              ("docbook-xsl" ,docbook-xsl)))
+              ("docbook-xsl" ,docbook-xsl)
+              ("libxml2" ,libxml2)
+              ("libxslt" ,libxslt)))
     (home-page "http://www.methods.co.nz/asciidoc/")
     (synopsis "Text-based document generation system")
     (description
diff --git a/gnu/packages/games.scm b/gnu/packages/games.scm
index 1ce18658d0..f8152e0184 100644
--- a/gnu/packages/games.scm
+++ b/gnu/packages/games.scm
@@ -2528,7 +2528,8 @@ Super Game Boy, BS-X Satellaview, and Sufami Turbo.")
                                                   "/bin/tar"))
                           (out     (assoc-ref %outputs "out"))
                           (bin     (string-append out "/bin"))
-                          (doc     (string-append out "/share/doc")))
+                          (doc     (string-append out
+                                                  "/share/doc/grue-hunter")))
                      (begin
                        (mkdir out)
                        (copy-file tarball "grue-hunter.tar.gz")
@@ -2542,8 +2543,7 @@ Super Game Boy, BS-X Satellaview, and Sufami Turbo.")
                                       (list perl))
 
                        (mkdir-p doc)
-                       (copy-file "grue-hunter/AGPLv3.txt"
-                                  (string-append doc "/grue-hunter")))))))
+                       (install-file "grue-hunter/AGPLv3.txt" doc))))))
     (inputs `(("perl" ,perl)
               ("tar" ,tar)
               ("gzip" ,gzip)
diff --git a/gnu/packages/gnustep.scm b/gnu/packages/gnustep.scm
index 8f72bb3253..6e729165c9 100644
--- a/gnu/packages/gnustep.scm
+++ b/gnu/packages/gnustep.scm
@@ -35,7 +35,7 @@
 (define-public windowmaker
   (package
     (name "windowmaker")
-    (version "0.95.7")
+    (version "0.95.8")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -43,40 +43,39 @@
                     version ".tar.gz"))
               (sha256
                (base32
-                "1acph0nq6fsb452sl7j7a7kcc87zqqaw7qms1p8ijar19dn4hbc4"))))
+                "12p8kljqgx5hnic0zvs5mxwp7kg21sb6qjagb2qw8ydvf5amrgwx"))))
     (build-system gnu-build-system)
     (arguments
-     '(#:phases (alist-cons-before
-                 'configure 'pre-configure
-                 (lambda* (#:key outputs #:allow-other-keys)
-                   ;; 'wmaker' wants to invoke 'wmaker.inst' the first time,
-                   ;; and the 'wmsetbg', so make sure it uses the right ones.
-                   ;; We can't use a wrapper here because that would pollute
-                   ;; $PATH in the whole session.
-                   (let* ((out (assoc-ref outputs "out"))
-                          (bin (string-append out "/bin")))
-                     (substitute* "src/main.c"
-                       (("\"wmaker\\.inst")
-                        (string-append "\"" bin "/wmaker.inst")))
-                     (substitute* '("src/defaults.c" "WPrefs.app/Menu.c")
-                       (("\"wmsetbg")
-                        (string-append "\"" bin "/wmsetbg")))
-                     ;; Add enough cells to the command character array to
-                     ;; allow passing our large path to the wmsetbg binary.
-                     ;; The path to wmsetbg in Guix requires 67 extra characters.
-                     (substitute* "src/defaults.c"
-                       (("len = strlen\\(text\\) \\+ 40;")
-                        (string-append "len = strlen(text) + 107;")))))
-                 (alist-cons-after
-                  'install 'wrap
-                  (lambda* (#:key outputs #:allow-other-keys)
-                    (let* ((out (assoc-ref outputs "out"))
-                           (bin (string-append out "/bin")))
-                      ;; In turn, 'wmaker.inst' wants to invoke 'wmmenugen'
-                      ;; etc., so make sure everything is in $PATH.
-                      (wrap-program (string-append bin "/wmaker.inst")
-                                    `("PATH" ":" prefix (,bin)))))
-                  %standard-phases))))
+     '(#:phases
+       (modify-phases %standard-phases
+         (add-before 'configure 'pre-configure
+           (lambda* (#:key outputs #:allow-other-keys)
+             ;; 'wmaker' wants to invoke 'wmaker.inst' the first time,
+             ;; and the 'wmsetbg', so make sure it uses the right ones.
+             ;; We can't use a wrapper here because that would pollute
+             ;; $PATH in the whole session.
+             (let* ((out (assoc-ref outputs "out"))
+                    (bin (string-append out "/bin")))
+               (substitute* "src/main.c"
+                 (("\"wmaker\\.inst")
+                  (string-append "\"" bin "/wmaker.inst")))
+               (substitute* '("src/defaults.c" "WPrefs.app/Menu.c")
+                 (("\"wmsetbg")
+                  (string-append "\"" bin "/wmsetbg")))
+               ;; Add enough cells to the command character array to
+               ;; allow passing our large path to the wmsetbg binary.
+               ;; The path to wmsetbg in Guix requires 67 extra characters.
+               (substitute* "src/defaults.c"
+                 (("len = strlen\\(text\\) \\+ 40;")
+                  (string-append "len = strlen(text) + 107;"))))))
+         (add-after 'install 'wrap
+            (lambda* (#:key outputs #:allow-other-keys)
+              (let* ((out (assoc-ref outputs "out"))
+                     (bin (string-append out "/bin")))
+                ;; In turn, 'wmaker.inst' wants to invoke 'wmmenugen'
+                ;; etc., so make sure everything is in $PATH.
+                (wrap-program (string-append bin "/wmaker.inst")
+                              `("PATH" ":" prefix (,bin)))))))))
     (inputs
      `(("libxmu" ,libxmu)
        ("libxft" ,libxft)
diff --git a/gnu/packages/gnuzilla.scm b/gnu/packages/gnuzilla.scm
index 55dfda4948..e6e24f6650 100644
--- a/gnu/packages/gnuzilla.scm
+++ b/gnu/packages/gnuzilla.scm
@@ -186,7 +186,7 @@ in the Mozilla clients.")
 (define-public nss
   (package
     (name "nss")
-    (version "3.29.3")
+    (version "3.29.2")
     (source (origin
               (method url-fetch)
               (uri (let ((version-with-underscores
@@ -197,7 +197,7 @@ in the Mozilla clients.")
                       "nss-" version ".tar.gz")))
               (sha256
                (base32
-                "1sz1r2iml9bhd4iqiqz75gii855a25895vpy9scjky0y4lqwrp9m"))
+                "149807rmzb76hnh48rw4m9jw83iw0168njzchz0hmbsgc8mk0i5w"))
               ;; Create nss.pc and nss-config.
               (patches (search-patches "nss-pkgconfig.patch"))))
     (build-system gnu-build-system)
@@ -221,52 +221,55 @@ in the Mozilla clients.")
                   (ice-9 match)
                   (srfi srfi-26))
        #:phases
-       (modify-phases %standard-phases
-         (replace 'configure
-           (lambda* (#:key system inputs #:allow-other-keys)
-             (setenv "CC" "gcc")
-             ;; Tells NSS to build for the 64-bit ABI if we are 64-bit system.
-             (when (string-prefix? "x86_64" system)
-               (setenv "USE_64" "1"))
-             #t))
-         (replace 'check
-           (lambda _
-             ;; Use 127.0.0.1 instead of $HOST.$DOMSUF as HOSTADDR for testing.
-             ;; The later requires a working DNS or /etc/hosts.
-             (setenv "DOMSUF" "(none)")
-             (setenv "USE_IP" "TRUE")
-             (setenv "IP_ADDRESS" "127.0.0.1")
-             (zero? (system* "./nss/tests/all.sh"))))
-           (replace 'install
-             (lambda* (#:key outputs #:allow-other-keys)
-               (let* ((out (assoc-ref outputs "out"))
-                      (bin (string-append (assoc-ref outputs "bin") "/bin"))
-                      (inc (string-append out "/include/nss"))
-                      (lib (string-append out "/lib/nss"))
-                      (obj (match (scandir "dist" (cut string-suffix? "OBJ" <>))
-                             ((obj) (string-append "dist/" obj)))))
-                 ;; Install nss-config to $out/bin.
-                 (install-file (string-append obj "/bin/nss-config")
-                               (string-append out "/bin"))
-                 (delete-file (string-append obj "/bin/nss-config"))
-                 ;; Install nss.pc to $out/lib/pkgconfig.
-                 (install-file (string-append obj "/lib/pkgconfig/nss.pc")
-                               (string-append out "/lib/pkgconfig"))
-                 (delete-file (string-append obj "/lib/pkgconfig/nss.pc"))
-                 (rmdir (string-append obj "/lib/pkgconfig"))
-                 ;; Install other files.
-                 (copy-recursively "dist/public/nss" inc)
-                 (copy-recursively (string-append obj "/bin") bin)
-                 (copy-recursively (string-append obj "/lib") lib)
+       (alist-replace
+        'configure
+        (lambda* (#:key system inputs #:allow-other-keys)
+          (setenv "CC" "gcc")
+          ;; Tells NSS to build for the 64-bit ABI if we are 64-bit system.
+          (when (string-prefix? "x86_64" system)
+            (setenv "USE_64" "1"))
+          #t)
+        (alist-replace
+         'check
+         (lambda _
+           ;; Use 127.0.0.1 instead of $HOST.$DOMSUF as HOSTADDR for testing.
+           ;; The later requires a working DNS or /etc/hosts.
+           (setenv "DOMSUF" "(none)")
+           (setenv "USE_IP" "TRUE")
+           (setenv "IP_ADDRESS" "127.0.0.1")
+           (zero? (system* "./nss/tests/all.sh")))
+         (alist-replace
+          'install
+          (lambda* (#:key outputs #:allow-other-keys)
+            (let* ((out (assoc-ref outputs "out"))
+                   (bin (string-append (assoc-ref outputs "bin") "/bin"))
+                   (inc (string-append out "/include/nss"))
+                   (lib (string-append out "/lib/nss"))
+                   (obj (match (scandir "dist" (cut string-suffix? "OBJ" <>))
+                          ((obj) (string-append "dist/" obj)))))
+              ;; Install nss-config to $out/bin.
+              (install-file (string-append obj "/bin/nss-config")
+                            (string-append out "/bin"))
+              (delete-file (string-append obj "/bin/nss-config"))
+              ;; Install nss.pc to $out/lib/pkgconfig.
+              (install-file (string-append obj "/lib/pkgconfig/nss.pc")
+                            (string-append out "/lib/pkgconfig"))
+              (delete-file (string-append obj "/lib/pkgconfig/nss.pc"))
+              (rmdir (string-append obj "/lib/pkgconfig"))
+              ;; Install other files.
+              (copy-recursively "dist/public/nss" inc)
+              (copy-recursively (string-append obj "/bin") bin)
+              (copy-recursively (string-append obj "/lib") lib)
 
-                 ;; FIXME: libgtest1.so is installed in the above step, and it's
-                 ;; (unnecessarily) linked with several NSS libraries, but
-                 ;; without the needed rpaths, causing the 'validate-runpath'
-                 ;; phase to fail.  Here we simply delete libgtest1.so, since it
-                 ;; seems to be used only during the tests.
-                 (delete-file (string-append lib "/libgtest1.so"))
+              ;; FIXME: libgtest1.so is installed in the above step, and it's
+              ;; (unnecessarily) linked with several NSS libraries, but
+              ;; without the needed rpaths, causing the 'validate-runpath'
+              ;; phase to fail.  Here we simply delete libgtest1.so, since it
+              ;; seems to be used only during the tests.
+              (delete-file (string-append lib "/libgtest1.so"))
 
-                 #t))))))
+              #t))
+          %standard-phases)))))
     (inputs
      `(("sqlite" ,sqlite)
        ("zlib" ,zlib)))
diff --git a/gnu/packages/gtk.scm b/gnu/packages/gtk.scm
index 057c808597..d724d79a85 100644
--- a/gnu/packages/gtk.scm
+++ b/gnu/packages/gtk.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013 Andreas Enge <andreas@enge.fr>
-;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2014, 2015, 2017 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2014 Eric Bavier <bavier@member.fsf.org>
 ;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
@@ -734,38 +734,52 @@ application suites.")
     (name "guile-cairo")
     (version "1.4.1")
     (source (origin
-             (method url-fetch)
-             (uri (string-append
-                   "http://download.gna.org/guile-cairo/guile-cairo-"
-                   version
-                   ".tar.gz"))
-             (sha256
-              (base32
-               "1f5nd9n46n6cwfl1byjml02q3y2hgn7nkx98km1czgwarxl7ws3x"))))
+              (method url-fetch)
+              (uri (string-append
+                    "http://download.gna.org/guile-cairo/guile-cairo-"
+                    version
+                    ".tar.gz"))
+              (sha256
+               (base32
+                "1f5nd9n46n6cwfl1byjml02q3y2hgn7nkx98km1czgwarxl7ws3x"))))
     (build-system gnu-build-system)
     (arguments
-     '(#:phases (alist-cons-before
-                 'configure 'set-module-directory
-                 (lambda* (#:key outputs #:allow-other-keys)
-                   ;; Install modules under $out/share/guile/site/2.0.
-                   (let ((out (assoc-ref outputs "out")))
-                     (substitute* "Makefile.in"
-                       (("scmdir = ([[:graph:]]+).*" _ value)
-                        (string-append "scmdir = " value "/2.0\n")))
-                     (substitute* "cairo/Makefile.in"
-                       (("moduledir = ([[:graph:]]+).*" _ value)
-                        (string-append "moduledir = "
-                                       "$(prefix)/share/guile/site/2.0/cairo\n'")))))
-                 (alist-cons-after
-                  'install 'install-missing-file
-                  (lambda* (#:key outputs #:allow-other-keys)
-                    ;; By default 'vector-types.scm' is not installed, so do
-                    ;; it here.
-                    (let ((out (assoc-ref outputs "out")))
-                      (copy-file "cairo/vector-types.scm"
-                                 (string-append out "/share/guile/site/2.0"
-                                                "/cairo/vector-types.scm"))))
-                  %standard-phases))))
+     '(#:modules ((guix build utils)
+                  (guix build gnu-build-system)
+                  (ice-9 popen)
+                  (ice-9 rdelim))
+
+       #:phases (modify-phases %standard-phases
+                  (add-before 'configure 'set-module-directory
+                    (lambda* (#:key outputs #:allow-other-keys)
+                      ;; Install modules under $out/share/guile/site/2.0.
+                      (let ((out (assoc-ref outputs "out"))
+                            (effective
+                             (read-line
+                              (open-pipe* OPEN_READ "guile" "-c"
+                                          "(display (effective-version))"))))
+                        (substitute* "Makefile.in"
+                          (("scmdir = ([[:graph:]]+).*" _ value)
+                           (string-append "scmdir = " value "/" effective "\n")))
+                        (substitute* "cairo/Makefile.in"
+                          (("moduledir = ([[:graph:]]+).*" _ value)
+                           (string-append "moduledir = "
+                                          "$(prefix)/share/guile/site/"
+                                          effective "/cairo\n'")))
+                        #t)))
+                  (add-after 'install 'install-missing-file
+                    (lambda* (#:key outputs #:allow-other-keys)
+                      ;; By default 'vector-types.scm' is not installed, so do
+                      ;; it here.
+                      (let ((out (assoc-ref outputs "out"))
+                            (effective
+                             (read-line
+                              (open-pipe* OPEN_READ "guile" "-c"
+                                          "(display (effective-version))"))))
+                        (install-file "cairo/vector-types.scm"
+                                      (string-append out "/share/guile/site/"
+                                                     effective "/cairo"))
+                        #t))))))
     (inputs
      `(("guile-lib" ,guile-lib)
        ("expat" ,expat)
@@ -774,7 +788,7 @@ application suites.")
      ;; The .pc file refers to 'cairo'.
      `(("cairo" ,cairo)))
     (native-inputs
-      `(("pkg-config" ,pkg-config)))
+     `(("pkg-config" ,pkg-config)))
     (home-page "http://www.nongnu.org/guile-cairo/")
     (synopsis "Cairo bindings for GNU Guile")
     (description
diff --git a/gnu/packages/guile.scm b/gnu/packages/guile.scm
index 13ff0e069a..5425ab9c75 100644
--- a/gnu/packages/guile.scm
+++ b/gnu/packages/guile.scm
@@ -656,6 +656,9 @@ for Guile\".")
     ;; details.
     (license license:gpl3+)))
 
+(define-public guile2.2-lib
+  (package-for-guile-2.2 guile-lib))
+
 (define-public guile-json
   (package
     (name "guile-json")
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm
index cd6d32f0fd..62b1971f02 100644
--- a/gnu/packages/linux.scm
+++ b/gnu/packages/linux.scm
@@ -370,8 +370,8 @@ It has been modified to remove all non-free binary blobs.")
                     #:configuration-file kernel-config))
 
 (define-public linux-libre-4.1
-  (make-linux-libre "4.1.38"
-                    "165kmzglhg63hn7y4q7r6cb2dpsljxiq1czvgyx0bkd1vd2bcvsa"
+  (make-linux-libre "4.1.39"
+                    "06pb3zpkfkc7pb7yh537vvzn8i9nhqyx58kqxv0wq23b4hhpza7d"
                     %intel-compatible-systems
                     #:configuration-file kernel-config
                     #:patches
@@ -1999,7 +1999,7 @@ compliance.")
 (define-public wireless-regdb
   (package
     (name "wireless-regdb")
-    (version "2016.06.10")
+    (version "2017.03.07")
     (source (origin
               (method url-fetch)
               (uri (string-append
@@ -2007,7 +2007,7 @@ compliance.")
                     "wireless-regdb-" version ".tar.xz"))
               (sha256
                (base32
-                "1dxqy7a7zpzya30ff00s8k1qgrlndrwys99gc0r8yg0vab1z3vfg"))
+                "1f9mcp78sdd4sci6v32vxfcl1rfjpv205jisz1p93kkfnaisy7ip"))
 
               ;; We're building 'regulatory.bin' by ourselves.
               (snippet '(delete-file "regulatory.bin"))))
diff --git a/gnu/packages/mail.scm b/gnu/packages/mail.scm
index 070d9ba093..fa8a3aae6b 100644
--- a/gnu/packages/mail.scm
+++ b/gnu/packages/mail.scm
@@ -44,6 +44,7 @@
   #:use-module (gnu packages backup)
   #:use-module (gnu packages bash)
   #:use-module (gnu packages bison)
+  #:use-module (gnu packages crypto)
   #:use-module (gnu packages curl)
   #:use-module (gnu packages cyrus-sasl)
   #:use-module (gnu packages databases)
@@ -93,7 +94,7 @@
                 #:select (gpl2 gpl2+ gpl3 gpl3+ lgpl2.1 lgpl2.1+ lgpl3+
                            non-copyleft (expat . license:expat) bsd-3
                            public-domain bsd-4 isc (openssl . license:openssl)
-                           bsd-2 x11-style))
+                           bsd-2 x11-style agpl3))
   #:use-module (guix packages)
   #:use-module (guix download)
   #:use-module (guix git-download)
@@ -1130,6 +1131,104 @@ It supports mbox/Maildir and its own dbox/mdbox formats.")
     ;; Unicode, Inc. License Agreement for Data Files and Software.
     (license (list lgpl2.1 license:expat (non-copyleft "file://COPYING")))))
 
+(define-public dovecot-trees
+  (let ((commit "006059c8a47d68f14f73c09743e45b9a73014dbf")
+        (revision "1"))
+    (package
+      (name "dovecot-trees")
+      (version (string-append "2.0.0-" revision "." (string-take commit 7)))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://0xacab.org/riseuplabs/trees.git")
+               (commit commit)))
+         (file-name (string-append name "-" version "-checkout"))
+         (sha256
+          (base32
+           "0ax90bzc66x179wi1m7ywqwa8nssyhjngs7ij109hqqxg5ymfp73"))))
+      (build-system gnu-build-system)
+      (native-inputs
+       `(("automake" ,automake)
+         ("autoconf" ,autoconf)
+         ("libtool" ,libtool)
+         ("dovecot" ,dovecot)
+         ("pkg-config" ,pkg-config)))
+      (inputs
+       `(("libsodium" ,libsodium)))
+      (arguments
+       `(#:tests? #f ;No tests exist.
+         #:configure-flags (list (string-append "--with-dovecot="
+                                                (assoc-ref %build-inputs "dovecot")
+                                                "/lib/dovecot"))
+         #:phases
+         (modify-phases %standard-phases
+           (add-before 'configure 'autogen
+             (lambda _
+               (zero? (system* "./autogen.sh")))))))
+      (home-page "https://0xacab.org/riseuplabs/trees")
+      (synopsis "NaCL-based Dovecot email storage encryption plugin")
+      (description
+       "Technology for Resting Email Encrypted Storage (TREES) is a NaCL-based
+Dovecot encryption plugin.  This plugin adds individually encrypted mail
+storage to the Dovecot IMAP server.  It is inspired by Posteo's scrambler
+which uses OpenSSL and RSA keypairs.  TREES works in a similar way, but uses
+the Sodium crypto library (based on NaCL).
+
+How it works:
+@enumerate
+@item On IMAP log in, the user's cleartext password is passed to the plugin.
+@item The plugin creates an argon2 digest from the password.
+@item This password digest is used as a symmetric secret to decrypt a libsodium secretbox.
+@item Inside the secretbox is stored a Curve25519 private key.
+@item The Curve25519 private key is used to decrypt each individual message,
+using lidsodium sealed boxes.
+@item New mail is encrypted as it arrives using the Curve25519 public key.
+@end enumerate\n")
+      (license agpl3))))
+
+(define-public dovecot-libsodium-plugin
+  (let ((commit "044de73c01c35385df0105f6b387bec5d5317ce7")
+        (revision "1"))
+    (package
+      (name "dovecot-libsodium-plugin")
+      (version (string-append "0.0.0-" revision "." (string-take commit 7)))
+      (source
+       (origin
+         (method git-fetch)
+         (uri (git-reference
+               (url "https://github.com/LuckyFellow/dovecot-libsodium-plugin")
+               (commit commit)))
+         (file-name (string-append name "-" version "-checkout"))
+         (sha256
+          (base32
+           "13h07l7xy713zchnj2p9fhvq7fdl4zy1ai94li3ygkqjjj8hrgas"))))
+      (build-system gnu-build-system)
+      (native-inputs
+       `(("automake" ,automake)
+         ("autoconf" ,autoconf)
+         ("libtool" ,libtool)
+         ("dovecot" ,dovecot)
+         ("pkg-config" ,pkg-config)))
+      (inputs
+       `(("libsodium" ,libsodium)))
+      (arguments
+       `(#:tests? #f ;No tests exist.
+         #:configure-flags (list (string-append "--with-dovecot="
+                                                (assoc-ref %build-inputs "dovecot")
+                                                "/lib/dovecot"))
+         #:phases
+         (modify-phases %standard-phases
+           (add-before 'configure 'autogen
+             (lambda _
+               (zero? (system* "./autogen.sh")))))))
+      (home-page "https://github.com/LuckyFellow/dovecot-libsodium-plugin")
+      (synopsis "Libsodium password hashing schemes plugin for Dovecot")
+      (description
+       "@code{dovecot-libsodium-plugin} provides libsodium password
+hashing schemes plugin for @code{Dovecot}.")
+      (license gpl3+))))
+
 (define-public isync
   (package
     (name "isync")
diff --git a/gnu/packages/messaging.scm b/gnu/packages/messaging.scm
index f2f36ad876..4e40567b1c 100644
--- a/gnu/packages/messaging.scm
+++ b/gnu/packages/messaging.scm
@@ -386,14 +386,14 @@ compromised.")
 (define-public znc
   (package
     (name "znc")
-    (version "1.6.4")
+    (version "1.6.5")
     (source (origin
               (method url-fetch)
               (uri (string-append "http://znc.in/releases/archive/znc-"
                                   version ".tar.gz"))
               (sha256
                (base32
-                "070d6b1i3jy66m4ci4ypxkg4pbwqbzbzss1y1ycgq2w62zmrf423"))))
+                "1jia6kq6bp8yxfj02d5vj9vqb4pylqcldspyjj6iz82kkka2a0ig"))))
     (build-system gnu-build-system)
     (arguments
      '(#:tests? #f ; tries to download GoogleTest with wget
diff --git a/gnu/packages/ocaml.scm b/gnu/packages/ocaml.scm
index e225aa6d68..ebc5caf254 100644
--- a/gnu/packages/ocaml.scm
+++ b/gnu/packages/ocaml.scm
@@ -2280,3 +2280,205 @@ than ocaml's Pervasives.compare.  Scaffolding functions also gives you more
 flexibility by allowing you to override them for a specific type and more safety
 by making sure that you only compare comparable values.")
     (license license:asl2.0)))
+
+(define-public ocaml-sexplib
+  (package
+    (name "ocaml-sexplib")
+    (version "113.33.03")
+    (source (janestreet-origin "sexplib" version
+              "1ffjmj8if9lyv965cgn2ld1xv7g52qsr8mqflbm515ck1i8l2ima"))
+    (build-system ocaml-build-system)
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/sexplib/")
+    (synopsis "Library for serializing OCaml values to and from S-expressions")
+    (description "Sexplib contains functionality for parsing and pretty-printing
+s-expressions.")
+    (license license:asl2.0)))
+
+(define-public ocaml-typerep
+  (package
+    (name "ocaml-typerep")
+    (version "113.33.03")
+    (source (janestreet-origin "typerep" version
+              "1b9v5bmi824a9d4sx0f40ixq0yfcbiqxafg4a1jx95xg9199zafy"))
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (build-system ocaml-build-system)
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/typerep/")
+    (synopsis "Typerep is a library for runtime types")
+    (description "Typerep is a library for runtime types.")
+    (license license:asl2.0)))
+
+(define-public ocaml-variantslib
+  (package
+    (name "ocaml-variantslib")
+    (version "113.33.03")
+    (source (janestreet-origin "variantslib" version
+              "05vp799vl38fvl98ga5miwbzh09cnnpapi6q6gdvwyqi6w7s919n"))
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (build-system ocaml-build-system)
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/variantslib")
+    (synopsis "OCaml variants as first class values")
+    (description "OCaml variants as first class values.")
+    (license license:asl2.0)))
+
+(define-public ocaml-ppx-sexp-conv
+  (package
+    (name "ocaml-ppx-sexp-conv")
+    (version "113.33.03")
+    (source (janestreet-origin "ppx_sexp_conv" version
+              "1rbj6d5dl625gdxih34xcrdvikci6h8i2dl9x3wraa4qrgishiw7"))
+    (build-system ocaml-build-system)
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)
+       ("ppx-core" ,ocaml-ppx-core)))
+    (propagated-inputs
+     `(("sexplib" ,ocaml-sexplib)
+       ("ppx-core" ,ocaml-ppx-core)
+       ("ppx-type-conv" ,ocaml-ppx-type-conv)
+       ("ppx-tools" ,ocaml-ppx-tools)))
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/ppx_sexp_conv")
+    (synopsis "Generation of S-expression conversion functions from type definitions")
+    (description "Generation of S-expression conversion functions from type
+definitions.")
+    (license license:asl2.0)))
+
+(define-public ocaml-ppx-variants-conv
+  (package
+    (name "ocaml-ppx-variants-conv")
+    (version "113.33.03")
+    (source (janestreet-origin "ppx_variants_conv" version
+              "0vnn2l1118cj72413d3f7frlw6yc09l8f64jlzkzbgb9bxpalx34"))
+    (build-system ocaml-build-system)
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (propagated-inputs
+     `(("ppx-core" ,ocaml-ppx-core)
+       ("variantslib" ,ocaml-variantslib)
+       ("ppx-tools" ,ocaml-ppx-tools)
+       ("ppx-type-conv" ,ocaml-ppx-type-conv)))
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/ppx_variants_conv")
+    (synopsis "Generation of accessor and iteration functions for ocaml variant
+types")
+    (description "Generation of accessor and iteration functions for ocaml
+variant types.")
+    (license license:asl2.0)))
+
+(define-public ocaml-ppx-here
+  (package
+    (name "ocaml-ppx-here")
+    (version "113.33.03")
+    (source (janestreet-origin "ppx_here" version
+              "1ay8lfxi0qg3ib2zkwh4h0vqk3gjmxaz572gzab0bbxyqn3z86v7"))
+    (build-system ocaml-build-system)
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (propagated-inputs
+     `(("ppx-driver" ,ocaml-ppx-driver)
+       ("ppx-core" ,ocaml-ppx-core)))
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/ppx_here")
+    (synopsis "Expands [%here] into its location")
+    (description "Expands [%here] into its location.")
+    (license license:asl2.0)))
+
+(define-public ocaml-ppx-assert
+  (package
+    (name "ocaml-ppx-assert")
+    (version "113.33.03")
+    (source (janestreet-origin "ppx_assert" version
+              "1k5kxmqkibp5fk25pgz81f3c1r4mgvb5byzf6bnmxd24y60wn46p"))
+    (build-system ocaml-build-system)
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (propagated-inputs
+     `(("ppx-compare" ,ocaml-ppx-compare)
+       ("ppx-core" ,ocaml-ppx-core)
+       ("ppx-driver" ,ocaml-ppx-driver)
+       ("ppx-sexp-conv" ,ocaml-ppx-sexp-conv)
+       ("ppx-tools" ,ocaml-ppx-tools)
+       ("ppx-type-conv" ,ocaml-ppx-type-conv)
+       ("ppx-sexplib" ,ocaml-sexplib)
+       ("ppx-here" ,ocaml-ppx-here)))
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/ppx_assert")
+    (synopsis "Assert-like extension nodes that raise useful errors on failure")
+    (description "Assert-like extension nodes that raise useful errors on failure.")
+    (license license:asl2.0)))
+
+(define-public ocaml-ppx-enumerate
+  (package
+    (name "ocaml-ppx-enumerate")
+    (version "113.33.03")
+    (source (janestreet-origin "ppx_enumerate" version
+              "15g7yfv9wg2h9r6k6q1zrhygmsl4xrfn25mrb0i4czjjivzmxjh4"))
+    (build-system ocaml-build-system)
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (propagated-inputs
+     `(("ppx-tools" ,ocaml-ppx-tools)
+       ("ppx-type-conv" ,ocaml-ppx-type-conv)
+       ("ppx-core" ,ocaml-ppx-core)))
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/ppx_enumerate")
+    (synopsis "Generate a list containing all values of a finite type")
+    (description "Ppx_enumerate is a ppx rewriter which generates a definition
+for the list of all values of a type (for a type which only has finitely
+many values).")
+    (license license:asl2.0)))
+
+(define-public ocaml-ppx-let
+  (package
+    (name "ocaml-ppx-let")
+    (version "113.33.03")
+    (source (janestreet-origin "ppx_let" version
+              "0gd6d3gdaqfwjcs7gaw1qxc30i584q6a86ndaj1bx1q63xqd6yx9"))
+    (build-system ocaml-build-system)
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (propagated-inputs
+     `(("ppx-driver" ,ocaml-ppx-driver)
+       ("ppx-core" ,ocaml-ppx-core)))
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/ppx_let")
+    (synopsis "Monadic let-bindings")
+    (description "A ppx rewriter for monadic and applicative let bindings,
+match expressions, and if expressions.")
+    (license license:asl2.0)))
+
+(define-public ocaml-ppx-typerep-conv
+  (package
+    (name "ocaml-ppx-typerep-conv")
+    (version "113.33.03")
+    (source (janestreet-origin "ppx_typerep_conv" version
+              "0g0xqm9s1b2jjvxb8yp69281q2s3bwz6sibn10fvgcdawpa0rmrg"))
+    (build-system ocaml-build-system)
+    (native-inputs
+     `(("js-build-tools" ,ocaml-js-build-tools)
+       ("opam" ,opam)))
+    (propagated-inputs
+     `(("ppx-tools" ,ocaml-ppx-tools)
+       ("ppx-type-conv" ,ocaml-ppx-type-conv)
+       ("ppx-core" ,ocaml-ppx-core)
+       ("typerep" ,ocaml-typerep)))
+    (arguments janestreet-arguments)
+    (home-page "https://github.com/janestreet/ppx_typerep_conv")
+    (synopsis "Generation of runtime types from type declarations")
+    (description "Automatic generation of runtime types from type definitions.")
+    (license license:asl2.0)))
diff --git a/gnu/packages/python.scm b/gnu/packages/python.scm
index fa4235703b..2b1255c2ec 100644
--- a/gnu/packages/python.scm
+++ b/gnu/packages/python.scm
@@ -1,6 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
-;;; Copyright © 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2013, 2014, 2015, 2016 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2014, 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2014, 2017 Eric Bavier <bavier@member.fsf.org>
@@ -1130,18 +1130,22 @@ datetime module, available in Python 2.3+.")
 (define-public python-parsedatetime
   (package
     (name "python-parsedatetime")
-    (version "2.1")
+    (version "2.3")
     (source
      (origin
       (method url-fetch)
       (uri (pypi-uri "parsedatetime" version))
       (sha256
        (base32
-        "0bdgyw6y3v7bcxlx0p50s8drxsh5bb5cy2afccqr3j90amvpii8p"))))
+        "1vkrmd398s11h1zn3zaqqsiqhj9lwy1ikcg6irx2lrgjzjg3rjll"))))
     (build-system python-build-system)
     (native-inputs
      `(("python-nose" ,python-nose)
-       ("python-pyicu" ,python-pyicu)))
+       ("python-pyicu" ,python-pyicu)
+       ("python-pytest" ,python-pytest)
+       ("python-pytest-runner" ,python-pytest-runner)))
+    (propagated-inputs
+     `(("python-future" ,python-future)))
     (home-page "http://github.com/bear/parsedatetime/")
     (synopsis
      "Parse human-readable date/time text")
@@ -6161,14 +6165,14 @@ so it might be a tiny bit slower.")
 (define-public python-waf
   (package
     (name "python-waf")
-    (version "1.9.5")
+    (version "1.9.8")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://waf.io/"
                                   "waf-" version ".tar.bz2"))
               (sha256
                (base32
-                "1sl3ipi2czds57rlzjnpdzqa0skx8asfvmh3qmibpvdwf15rpppg"))))
+                "0wl4cnmp06lfxqjxaan58bqxn27smhydz0sg5prrfbl3bsw4gv6q"))))
     (build-system python-build-system)
     (arguments
      '(#:phases
@@ -6182,7 +6186,7 @@ so it might be a tiny bit slower.")
          (replace 'install
            (lambda _
              (copy-file "waf" %output))))))
-    (home-page "http://waf.io/")
+    (home-page "https://waf.io/")
     (synopsis "Python-based build system")
     (description
      "Waf is a Python-based framework for configuring, compiling and installing
diff --git a/gnu/packages/shellutils.scm b/gnu/packages/shellutils.scm
index e69df7d832..3ecc1ee8ba 100644
--- a/gnu/packages/shellutils.scm
+++ b/gnu/packages/shellutils.scm
@@ -94,7 +94,7 @@ are already there.")
 (define-public direnv
   (package
     (name "direnv")
-    (version "2.10.0")
+    (version "2.11.3")
     (source
      (origin (method url-fetch)
              (uri (string-append "https://github.com/direnv/" name
@@ -102,7 +102,7 @@ are already there.")
              (file-name (string-append name "-" version ".tar.gz"))
              (sha256
               (base32
-               "1h5ywn0glw1kmxs3jwjv9fvnhha942c6k740p5ghvyns05ds9cqf"))))
+               "01mhwzq9ss2qlnn8aahvwsgnspq8hbz0qfknf290aicngwx10d1d"))))
     (build-system gnu-build-system)
     (arguments
      '(#:test-target "test"
diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm
index 7f352d0b0b..aee424fbc9 100644
--- a/gnu/packages/version-control.scm
+++ b/gnu/packages/version-control.scm
@@ -617,17 +617,6 @@ also walk each side of a merge and test those changes individually.")
                         (substitute* (find-files "." ".*")
                           ((" perl -")
                            (string-append " " perl " -"))))))
-                  (add-before 'install 'fix-hooks-shebangs
-                    (lambda* (#:key inputs #:allow-other-keys)
-                      (let ((perl (string-append (assoc-ref inputs "perl")
-                                                 "/bin/perl")))
-                        ;; The files in 'lib/Gitolite/Hooks' keep references to
-                        ;; '/usr/bin/perl', without this fix it is impossible to
-                        ;; to run gitolite in production.
-                        (substitute* (find-files "src/lib/Gitolite/Hooks" ".*")
-                          (("/usr/bin/perl")
-                           perl))
-                        #t)))
                   (replace 'install
                     (lambda* (#:key outputs #:allow-other-keys)
                       (let* ((output (assoc-ref outputs "out"))
diff --git a/gnu/packages/video.scm b/gnu/packages/video.scm
index 34ffabb483..2988773398 100644
--- a/gnu/packages/video.scm
+++ b/gnu/packages/video.scm
@@ -980,7 +980,7 @@ access to mpv's powerful playback capabilities.")
 (define-public youtube-dl
   (package
     (name "youtube-dl")
-    (version "2017.03.07")
+    (version "2017.03.15")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://yt-dl.org/downloads/"
@@ -988,7 +988,7 @@ access to mpv's powerful playback capabilities.")
                                   version ".tar.gz"))
               (sha256
                (base32
-                "19acz9m3gazd1ims4l9a9ni1p7jw8z4y0ncqn99xlx9kna8ryjnv"))))
+                "0h561pbphdkfalir9awp0k4fmsnzdf6kx56adb9bb0v9pfsb1y0f"))))
     (build-system python-build-system)
     (arguments
      ;; The problem here is that the directory for the man page and completion
@@ -1495,7 +1495,7 @@ be used for realtime video capture via Linux-specific APIs.")
 (define-public obs
   (package
     (name "obs")
-    (version "18.0.0")
+    (version "18.0.1")
     (source (origin
               (method url-fetch)
               (uri (string-append "https://github.com/jp9000/obs-studio"
@@ -1503,7 +1503,7 @@ be used for realtime video capture via Linux-specific APIs.")
               (file-name (string-append name "-" version ".tar.gz"))
               (sha256
                (base32
-                "0pxrzzp8z7kmwfdp49rwrk0j3lpya6garvbbzzfvldwhyam9az5d"))))
+                "043f8mfdh4ll0hpivpyg3iniirckwsgri0gzamyrba1yhf2c2ibr"))))
     (build-system cmake-build-system)
     (arguments
      `(#:tests? #f ; no tests
diff --git a/gnu/packages/w3m.scm b/gnu/packages/w3m.scm
index 12114b13b9..0489212197 100644
--- a/gnu/packages/w3m.scm
+++ b/gnu/packages/w3m.scm
@@ -36,7 +36,7 @@
 (define-public w3m
   (package
     (name "w3m")
-    (version "0.5.3+git20161120")
+    (version "0.5.3+git20170102")
     (source (origin
               (method git-fetch)
               ;; Debian's fork of w3m is the only one that is still
@@ -47,7 +47,7 @@
               (file-name (string-append "w3m-" version "-checkout"))
               (sha256
                (base32
-                "06n5a9jdyihkd4xdjmyci32dpqp1k2l5awia5g9ng0bn256bacdc"))))
+                "0p8csd49b550q69bk45ncs2y2x48xij7jj11xapp0s8dn1j7kcgx"))))
     (build-system gnu-build-system)
     (arguments
      '(#:tests? #f  ; no check target
diff --git a/guix/build/download.scm b/guix/build/download.scm
index 203338b527..e7a7afecd1 100644
--- a/guix/build/download.scm
+++ b/guix/build/download.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Mark H Weaver <mhw@netris.org>
 ;;; Copyright © 2015 Steve Sprang <scs@stevesprang.com>
 ;;;
@@ -37,6 +37,7 @@
   #:use-module (ice-9 format)
   #:export (open-socket-for-uri
             open-connection-for-uri
+            %x509-certificate-directory
             close-connection
             resolve-uri-reference
             maybe-expand-mirrors
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 58c23f2844..5aae1530f4 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -656,6 +656,36 @@ mounted at FILE."
 (define CLONE_NEWPID         #x20000000)
 (define CLONE_NEWNET         #x40000000)
 
+(cond-expand
+  (guile-2.2
+   (define %set-automatic-finalization-enabled?!
+     (let ((proc (pointer->procedure int
+                                     (dynamic-func
+                                      "scm_set_automatic_finalization_enabled"
+                                      (dynamic-link))
+                                     (list int))))
+       (lambda (enabled?)
+         "Switch on or off automatic finalization in a separate thread.
+Turning finalization off shuts down the finalization thread as a side effect."
+         (->bool (proc (if enabled? 1 0))))))
+
+   (define-syntax-rule (without-automatic-finalization exp)
+     "Turn off automatic finalization within the dynamic extent of EXP."
+     (let ((enabled? #t))
+       (dynamic-wind
+         (lambda ()
+           (set! enabled? (%set-automatic-finalization-enabled?! #f)))
+         (lambda ()
+           exp)
+         (lambda ()
+           (%set-automatic-finalization-enabled?! enabled?))))))
+
+  (else
+   (define-syntax-rule (without-automatic-finalization exp)
+     ;; Nothing to do here: Guile 2.0 does not have a separate finalization
+     ;; thread.
+     exp)))
+
 ;; The libc interface to sys_clone is not useful for Scheme programs, so the
 ;; low-level system call is wrapped instead.  The 'syscall' function is
 ;; declared in <unistd.h> as a variadic function; in practice, it expects 6
@@ -678,10 +708,17 @@ mounted at FILE."
 Unlike the fork system call, clone accepts FLAGS that specify which resources
 are shared between the parent and child processes."
       (let-values (((ret err)
-                    (proc syscall-id flags
-                          %null-pointer                     ;child stack
-                          %null-pointer %null-pointer       ;ptid & ctid
-                          %null-pointer)))                  ;unused
+                    ;; Guile 2.2 runs a finalization thread.  'primitive-fork'
+                    ;; takes care of shutting it down before forking, and we
+                    ;; must do the same here.  Failing to do that, if the
+                    ;; child process calls 'primitive-fork', it will hang
+                    ;; while trying to pthread_join the finalization thread
+                    ;; since that thread does not exist.
+                    (without-automatic-finalization
+                     (proc syscall-id flags
+                           %null-pointer              ;child stack
+                           %null-pointer %null-pointer ;ptid & ctid
+                           %null-pointer))))           ;unused
         (if (= ret -1)
             (throw 'system-error "clone" "~d: ~A"
                    (list flags (strerror err))
diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm
index e8f3d800a8..067b1227e0 100644
--- a/guix/scripts/pack.scm
+++ b/guix/scripts/pack.scm
@@ -43,20 +43,19 @@
 
 ;; Type of a compression tool.
 (define-record-type <compressor>
-  (compressor name package extension tar-option)
+  (compressor name package extension command)
   compressor?
   (name       compressor-name)                    ;string (e.g., "gzip")
   (package    compressor-package)                 ;package
   (extension  compressor-extension)               ;string (e.g., "lz")
-  (tar-option compressor-tar-option))             ;string (e.g., "--lzip")
+  (command    compressor-command))                ;list (e.g., '("gzip" "-9n"))
 
 (define %compressors
   ;; Available compression tools.
-  ;; FIXME: Use '--no-name' for gzip.
-  (list (compressor "gzip"  gzip  "gz"  "--gzip")
-        (compressor "lzip"  lzip  "lz"  "--lzip")
-        (compressor "xz"    xz    "xz"  "--xz")
-        (compressor "bzip2" bzip2 "bz2" "--bzip2")))
+  (list (compressor "gzip"  gzip  "gz"  '("gzip" "-9n"))
+        (compressor "lzip"  lzip  "lz"  '("lzip" "-9"))
+        (compressor "xz"    xz    "xz"  '("xz" "-e"))
+        (compressor "bzip2" bzip2 "bz2" '("bzip2" "-9"))))
 
 (define (lookup-compressor name)
   "Return the compressor object called NAME.  Error out if it could not be
@@ -69,23 +68,57 @@ found."
 
 (define* (self-contained-tarball name profile
                                  #:key deduplicate?
-                                 (compressor (first %compressors)))
+                                 (compressor (first %compressors))
+                                 localstatedir?
+                                 (symlinks '())
+                                 (tar tar))
   "Return a self-contained tarball containing a store initialized with the
-closure of PROFILE, a derivation.  The tarball contains /gnu/store, /var/guix,
-and PROFILE is available as /root/.guix-profile."
+closure of PROFILE, a derivation.  The tarball contains /gnu/store; if
+LOCALSTATEDIR? is true, it also contains /var/guix, including /var/guix/db
+with a properly initialized store database.
+
+SYMLINKS must be a list of (SOURCE -> TARGET) tuples denoting symlinks to be
+added to the pack."
   (define build
     (with-imported-modules '((guix build utils)
                              (guix build store-copy)
                              (gnu build install))
       #~(begin
           (use-modules (guix build utils)
-                       (gnu build install))
+                       (gnu build install)
+                       (srfi srfi-1)
+                       (srfi srfi-26)
+                       (ice-9 match))
 
           (define %root "root")
 
+          (define symlink->directives
+            ;; Return "populate directives" to make the given symlink and its
+            ;; parent directories.
+            (match-lambda
+              ((source '-> target)
+               (let ((target (string-append #$profile "/" target)))
+                 `((directory ,(dirname source))
+                   (,source -> ,target))))))
+
+          (define directives
+            ;; Fully-qualified symlinks.
+            (append-map symlink->directives '#$symlinks))
+
+          ;; The --sort option was added to GNU tar in version 1.28, released
+          ;; 2014-07-28.  For testing, we use the bootstrap tar, which is
+          ;; older and doesn't support it.
+          (define tar-supports-sort?
+            (zero? (system* (string-append #+tar "/bin/tar")
+                            "cf" "/dev/null" "--files-from=/dev/null"
+                            "--sort=name")))
+
           ;; We need Guix here for 'guix-register'.
           (setenv "PATH"
-                  (string-append #$guix "/sbin:" #$tar "/bin:"
+                  (string-append #$(if localstatedir?
+                                       (file-append guix "/sbin:")
+                                       "")
+                                 #$tar "/bin:"
                                  #$(compressor-package compressor) "/bin"))
 
           ;; Note: there is not much to gain here with deduplication and
@@ -94,33 +127,50 @@ and PROFILE is available as /root/.guix-profile."
           (populate-single-profile-directory %root
                                              #:profile #$profile
                                              #:closure "profile"
-                                             #:deduplicate? #f)
+                                             #:deduplicate? #f
+                                             #:register? #$localstatedir?)
+
+          ;; Create SYMLINKS.
+          (for-each (cut evaluate-populate-directive <> %root)
+                    directives)
 
           ;; Create the tarball.  Use GNU format so there's no file name
           ;; length limitation.
           (with-directory-excursion %root
-            (zero? (system* "tar" #$(compressor-tar-option compressor)
-                            "--format=gnu"
-
-                            ;; Avoid non-determinism in the archive.  Use
-                            ;; mtime = 1, not zero, because that is what the
-                            ;; daemon does for files in the store (see the
-                            ;; 'mtimeStore' constant in local-store.cc.)
-                            "--sort=name"
-                            "--mtime=@1"          ;for files in /var/guix
-                            "--owner=root:0"
-                            "--group=root:0"
-
-                            "--check-links"
-                            "-cvf" #$output
-                            ;; Avoid adding / and /var to the tarball, so
-                            ;; that the ownership and permissions of those
-                            ;; directories will not be overwritten when
-                            ;; extracting the archive.  Do not include /root
-                            ;; because the root account might have a
-                            ;; different home directory.
-                            "./var/guix"
-                            (string-append "." (%store-directory))))))))
+            (exit
+             (zero? (apply system* "tar"
+                           "-I" #$(string-join (compressor-command compressor))
+                           "--format=gnu"
+
+                           ;; Avoid non-determinism in the archive.  Use
+                           ;; mtime = 1, not zero, because that is what the
+                           ;; daemon does for files in the store (see the
+                           ;; 'mtimeStore' constant in local-store.cc.)
+                           (if tar-supports-sort? "--sort=name" "--mtime=@1")
+                           "--mtime=@1"           ;for files in /var/guix
+                           "--owner=root:0"
+                           "--group=root:0"
+
+                           "--check-links"
+                           "-cvf" #$output
+                           ;; Avoid adding / and /var to the tarball, so
+                           ;; that the ownership and permissions of those
+                           ;; directories will not be overwritten when
+                           ;; extracting the archive.  Do not include /root
+                           ;; because the root account might have a
+                           ;; different home directory.
+                           #$@(if localstatedir?
+                                  '("./var/guix")
+                                  '())
+
+                           (string-append "." (%store-directory))
+
+                           (delete-duplicates
+                            (filter-map (match-lambda
+                                          (('directory directory)
+                                           (string-append "." directory))
+                                          (_ #f))
+                                        directives)))))))))
 
   (gexp->derivation (string-append name ".tar."
                                    (compressor-extension compressor))
@@ -140,6 +190,7 @@ and PROFILE is available as /root/.guix-profile."
     (graft? . #t)
     (max-silent-time . 3600)
     (verbosity . 0)
+    (symlinks . ())
     (compressor . ,(first %compressors))))
 
 (define %options
@@ -163,6 +214,22 @@ and PROFILE is available as /root/.guix-profile."
                  (lambda (opt name arg result)
                    (alist-cons 'compressor (lookup-compressor arg)
                                result)))
+         (option '(#\S "symlink") #t #f
+                 (lambda (opt name arg result)
+                   (match (string-tokenize arg
+                                           (char-set-complement
+                                            (char-set #\=)))
+                     ((source target)
+                      (let ((symlinks (assoc-ref result 'symlinks)))
+                        (alist-cons 'symlinks
+                                    `((,source -> ,target) ,@symlinks)
+                                    (alist-delete 'symlinks result eq?))))
+                     (x
+                      (leave (_ "~a: invalid symlink specification~%")
+                             arg)))))
+         (option '("localstatedir") #f #f
+                 (lambda (opt name arg result)
+                   (alist-cons 'localstatedir? #t result)))
 
          (append %transformation-options
                  %standard-build-options)))
@@ -178,6 +245,10 @@ Create a bundle of PACKAGE.\n"))
   -s, --system=SYSTEM    attempt to build for SYSTEM--e.g., \"i686-linux\""))
   (display (_ "
   -C, --compression=TOOL compress using TOOL--e.g., \"lzip\""))
+  (display (_ "
+  -S, --symlink=SPEC     create symlinks to the profile according to SPEC"))
+  (display (_ "
+      --localstatedir    include /var/guix in the resulting pack"))
   (newline)
   (display (_ "
   -h, --help             display this help and exit"))
@@ -209,14 +280,20 @@ Create a bundle of PACKAGE.\n"))
                                     (specification->package+output spec))
                                 list))
                             specs))
-             (compressor (assoc-ref opts 'compressor)))
+             (compressor (assoc-ref opts 'compressor))
+             (symlinks   (assoc-ref opts 'symlinks))
+             (localstatedir? (assoc-ref opts 'localstatedir?)))
         (with-store store
           (run-with-store store
             (mlet* %store-monad ((profile (profile-derivation
                                            (packages->manifest packages)))
                                  (drv (self-contained-tarball "pack" profile
                                                               #:compressor
-                                                              compressor)))
+                                                              compressor
+                                                              #:symlinks
+                                                              symlinks
+                                                              #:localstatedir?
+                                                              localstatedir?)))
               (mbegin %store-monad
                 (show-what-to-build* (list drv)
                                      #:use-substitutes?
diff --git a/guix/upstream.scm b/guix/upstream.scm
index 2334c4c0a6..a47a52be3f 100644
--- a/guix/upstream.scm
+++ b/guix/upstream.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2015 Alex Kost <alezost@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -131,7 +131,7 @@ correspond to the same version."
   "Return an updater among UPDATERS that matches PACKAGE, or #f if none of
 them matches."
   (any (match-lambda
-         (($ <upstream-updater> _ _ pred latest)
+         (($ <upstream-updater> name description pred latest)
           (and (pred package) latest)))
        updaters))
 
diff --git a/guix/zlib.scm b/guix/zlib.scm
index 74420129f6..3d830ef84e 100644
--- a/guix/zlib.scm
+++ b/guix/zlib.scm
@@ -149,21 +149,6 @@ the number of uncompressed bytes written, a strictly positive integer."
   ;; Z_DEFAULT_COMPRESSION.
   -1)
 
-(define (close-procedure gzfile port)
-  "Return a procedure that closes GZFILE, ensuring its underlying PORT is
-closed even if closing GZFILE triggers an exception."
-  (lambda ()
-    (catch 'zlib-error
-      (lambda ()
-        ;; 'gzclose' closes the underlying file descriptor.  'close-port'
-        ;; calls close(2), gets EBADF, which is ignores.
-        (gzclose gzfile)
-        (close-port port))
-      (lambda args
-        ;; Make sure PORT is closed despite the zlib error.
-        (close-port port)
-        (apply throw args)))))
-
 (define* (make-gzip-input-port port #:key (buffer-size %default-buffer-size))
   "Return an input port that decompresses data read from PORT, a file port.
 PORT is automatically closed when the resulting port is closed.  BUFFER-SIZE
@@ -173,7 +158,11 @@ buffered input, which would be lost (and is lost anyway)."
   (define gzfile
     (match (drain-input port)
       (""                                         ;PORT's buffer is empty
-       (gzdopen (fileno port) "r"))
+       ;; Since 'gzclose' will eventually close the file descriptor beneath
+       ;; PORT, we increase PORT's revealed count and never call 'close-port'
+       ;; on PORT since we would get EBADF if 'gzclose' already closed it (on
+       ;; 2.0 EBADF is swallowed by 'fport_close' but on 2.2 it is raised).
+       (gzdopen (port->fdes port) "r"))
       (_
        ;; This is unrecoverable but it's better than having the buffered input
        ;; be lost, leading to unclear end-of-file or corrupt-data errors down
@@ -188,7 +177,8 @@ buffered input, which would be lost (and is lost anyway)."
     (gzbuffer! gzfile buffer-size))
 
   (make-custom-binary-input-port "gzip-input" read! #f #f
-                                 (close-procedure gzfile port)))
+                                 (lambda ()
+                                   (gzclose gzfile))))
 
 (define* (make-gzip-output-port port
                                 #:key
@@ -200,7 +190,7 @@ port is closed."
   (define gzfile
     (begin
       (force-output port)                         ;empty PORT's buffer
-      (gzdopen (fileno port)
+      (gzdopen (port->fdes port)
                (string-append "w" (number->string level)))))
 
   (define (write! bv start count)
@@ -210,7 +200,8 @@ port is closed."
     (gzbuffer! gzfile buffer-size))
 
   (make-custom-binary-output-port "gzip-output" write! #f #f
-                                  (close-procedure gzfile port)))
+                                  (lambda ()
+                                    (gzclose gzfile))))
 
 (define* (call-with-gzip-input-port port proc
                                     #:key (buffer-size %default-buffer-size))
diff --git a/po/guix/POTFILES.in b/po/guix/POTFILES.in
index 0a2eee8170..bc78c3e303 100644
--- a/po/guix/POTFILES.in
+++ b/po/guix/POTFILES.in
@@ -25,6 +25,7 @@ guix/scripts/size.scm
 guix/scripts/graph.scm
 guix/scripts/challenge.scm
 guix/scripts/copy.scm
+guix/scripts/pack.scm
 guix/gnu-maintenance.scm
 guix/scripts/container.scm
 guix/scripts/container/exec.scm
diff --git a/tests/guix-system.sh b/tests/guix-system.sh
index 77d4e28999..de6db0928c 100644
--- a/tests/guix-system.sh
+++ b/tests/guix-system.sh
@@ -76,7 +76,14 @@ EOF
 if guix system build "$tmpfile" -n 2> "$errorfile"
 then false
 else
-    grep "$tmpfile:9:.*[Uu]nbound variable.*GRUB-config" "$errorfile"
+    if test "`guile -c '(display (effective-version))'`" = 2.2
+    then
+	# FIXME: With Guile 2.2.0 the error is reported on line 4.
+	# See <http://bugs.gnu.org/26107>.
+	grep "$tmpfile:[49]:.*[Uu]nbound variable.*GRUB-config" "$errorfile"
+    else
+	grep "$tmpfile:9:.*[Uu]nbound variable.*GRUB-config" "$errorfile"
+    fi
 fi
 
 OS_BASE='
diff --git a/tests/pack.scm b/tests/pack.scm
new file mode 100644
index 0000000000..de9ef8e6ab
--- /dev/null
+++ b/tests/pack.scm
@@ -0,0 +1,79 @@
+;;; 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-pack)
+  #:use-module (guix scripts pack)
+  #:use-module (guix store)
+  #:use-module (guix derivations)
+  #:use-module (guix profiles)
+  #:use-module (guix monads)
+  #:use-module (guix grafts)
+  #:use-module (guix tests)
+  #:use-module (guix gexp)
+  #:use-module (gnu packages bootstrap)
+  #:use-module (srfi srfi-64))
+
+(define %store
+  (open-connection-for-tests))
+
+;; Globally disable grafts because they can trigger early builds.
+(%graft? #f)
+
+(define-syntax-rule (test-assertm name exp)
+  (test-assert name
+    (run-with-store %store exp
+                    #:guile-for-build (%guile-for-build))))
+
+(define %gzip-compressor
+  ;; Compressor that uses the bootstrap 'gzip'.
+  ((@ (guix scripts pack) compressor) "gzip"
+   %bootstrap-coreutils&co "gz" '("gzip" "-6n")))
+
+(define %tar-bootstrap %bootstrap-coreutils&co)
+
+
+(test-begin "pack")
+
+(test-assertm "self-contained-tarball"
+  (mlet* %store-monad
+      ((profile (profile-derivation (packages->manifest
+                                     (list %bootstrap-guile))
+                                    #:hooks '()
+                                    #:locales? #f))
+       (tarball (self-contained-tarball "pack" profile
+                                        #:symlinks '(("/bin/Guile"
+                                                      -> "bin/guile"))
+                                        #:compressor %gzip-compressor
+                                        #:tar %tar-bootstrap))
+       (check   (gexp->derivation
+                 "check-tarball"
+                 #~(let ((guile (string-append "." #$profile "/bin")))
+                     (setenv "PATH"
+                             (string-append #$%tar-bootstrap "/bin"))
+                     (system* "tar" "xvf" #$tarball)
+                     (mkdir #$output)
+                     (exit
+                      (and (file-exists? (string-append guile "/guile"))
+                           (string=? (string-append #$%bootstrap-guile "/bin")
+                                     (readlink guile))
+                           (string=? (string-append (string-drop guile 1)
+                                                    "/guile")
+                                     (readlink "bin/Guile"))))))))
+    (built-derivations (list check))))
+
+(test-end)
diff --git a/tests/store.scm b/tests/store.scm
index 64d3553f25..c0ebe7b941 100644
--- a/tests/store.scm
+++ b/tests/store.scm
@@ -383,7 +383,9 @@
                      (package-derivation %store %bootstrap-guile))))
             (guard (c ((nix-protocol-error? c) #t))
               (build-derivations %store (list d))))))))
-   "garbage: ?lambda: λ"))
+   (cond-expand
+     (guile-2.0 "garbage: ?lambda: λ")
+     (else      "garbage: �lambda: λ"))))
 
 (test-assert "log-file, derivation"
   (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '()))
diff --git a/tests/zlib.scm b/tests/zlib.scm
index 5455240a71..f71609b7c5 100644
--- a/tests/zlib.scm
+++ b/tests/zlib.scm
@@ -57,7 +57,16 @@
               (match (waitpid pid)
                 ((_ . status)
                  (and (zero? status)
-                      (port-closed? parent)
+
+                      ;; PORT itself isn't closed but its underlying file
+                      ;; descriptor must have been closed by 'gzclose'.
+                      (catch 'system-error
+                        (lambda ()
+                          (seek (fileno parent) 0 SEEK_CUR)
+                          #f)
+                        (lambda args
+                          (= EBADF (system-error-errno args))))
+
                       (bytevector=? received data))))))))))))
 
 (test-end)