;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès ;;; ;;; 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 . (define-module (test-store) #:use-module (guix tests) #:use-module (guix config) #:use-module (guix store) #:use-module (guix utils) #:use-m
aboutsummaryrefslogtreecommitdiff
# htmlxref.cnf - reference file for free Texinfo manuals on the web.
# Modified by Ludovic Courtès <ludo@gnu.org> for the GNU Guix manual.

htmlxrefversion=2024-06-02.15; # UTC

# Copyright 2010-2020, 2022 Free Software Foundation, Inc.
# 
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
#
# The latest version of this file is available at
# http://ftpmirror.gnu.org/texinfo/htmlxref.cnf.
# Email corrections or additions to bug-texinfo@gnu.org.
# The primary goal is to list all relevant GNU manuals;
# other free manuals are also welcome.
#
# To be included in this list, a manual must:
#
# - have a generic url, e.g., no version numbers;
# - have a unique file name (e.g., manual identifier), i.e., be related to the
#   package name.  Things like "refman" or "tutorial" don't work.
# - follow the naming convention for nodes described at
# http://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref.html
#   This is what makeinfo and texi2html implement.
# 
# Unless the above criteria are met, it's not possible to generate
# reliable cross-manual references.
# 
# For information on automatically generating all the useful formats for
# a manual to put on the web, see
# http://www.gnu.org/prep/maintain/html_node/Manuals-on-Web-Pages.html.

# For people editing this file: when a manual named foo is related to a
# package named bar, the url should contain a variable reference ${BAR}.
# Otherwise, the gnumaint scripts have no way of knowing they are
# associated, and thus gnu.org/manual can't include them.

# shorten references to manuals on www.gnu.org.
G = https://www.gnu.org
GS = ${G}/software

3dldf		mono	${GS}/3dldf/manual/user_ref/3DLDF.html
3dldf		node	${GS}/3dldf/manual/user_ref/

alive		mono	${GS}/alive/manual/alive.html
alive		node	${GS}/alive/manual/html_node/

anubis		chapter	${GS}/anubis/manual/html_chapter/
anubis		section	${GS}/anubis/manual/html_section/
anubis		node	${GS}/anubis/manual/html_node/

artanis		mono	${GS}/artanis/manual/artanis.html
artanis		node	${GS}/artanis/manual/html_node/

aspell		section	http://aspell.net/man-html/index.html

auctex		mono	${GS}/auctex/manual/auctex.html
auctex		node	${GS}/auctex/manual/auctex/

autoconf	mono	${GS}/autoconf/manual/autoconf.html
autoconf	node	${GS}/autoconf/manual/html_node/

autogen		mono	${GS}/autogen/manual/html_mono/autogen.html
autogen		chapter	${GS}/autogen/manual/html_chapter/
autogen		node	${GS}/autoconf/manual/html_node/

automake	mono	${GS}/automake/manual/automake.html
automake	node	${GS}/automake/manual/html_node/

avl		node	http://adtinfo.org/libavl.html/

bash		mono	${GS}/bash/manual/bash.html
bash		node	${GS}/bash/manual/html_node/

BINUTILS = https://sourceware.org/binutils/docs
binutils	node	${BINUTILS}/binutils/
 as		node	${BINUTILS}/as/
 bfd		node	${BINUTILS}/bfd/
 gprof		node	${BINUTILS}/gprof/
 ld		node	${BINUTILS}/ld/

bison		mono	${GS}/bison/manual/bison.html
bison		node	${GS}/bison/manual/html_node/

bpel2owfn	mono	${GS}/bpel2owfn/manual/2.0.x/bpel2owfn.html

ccd2cue		mono	${GS}/ccd2cue/manual/ccd2cue.html
ccd2cue		node	${GS}/ccd2cue/manual/html_node/

cflow		mono	${GS}/cflow/manual/cflow.html
cflow		node	${GS}/cflow/manual/html_node/

chess		mono	${GS}/chess/manual/gnuchess.html
chess		node	${GS}/chess/manual/html_node/

combine		mono	${GS}/combine/manual/combine.html
combine		chapter	${GS}/combine/manual/html_chapter/
combine		section	${GS}/combine/manual/html_section/
combine		node	${GS}/combine/manual/html_node/

complexity	mono	${GS}/complexity/manual/complexity.html
complexity	node	${GS}/complexity/manual/html_node/

coreutils	mono	${GS}/coreutils/manual/coreutils
coreutils	node	${GS}/coreutils/manual/html_node/

cpio		mono	${GS}/cpio/manual/cpio
cpio		node	${GS}/cpio/manual/html_node/

cssc		node	${GS}/cssc/manual/

CUIRASS = ${GS}/guix/cuirass/manual
 cuirass	mono	${CUIRASS}/cuirass.html
 cuirass	node	${CUIRASS}/html_node/

CVS = ${GS}/trans-coord/manual
cvs            mono    ${CVS}/cvs/cvs.html
cvs            node    ${CVS}/cvs/html_node/

ddd		mono	${GS}/ddd/manual/html_mono/ddd.html

ddrescue	mono	${GS}/ddrescue/manual/ddrescue_manual.html

dejagnu         node    ${GS}/dejagnu/manual/

DICO = https://puszcza.gnu.org.ua/software/dico/manual
dico		mono	${DICO}/dico.html
dico		chapter	${DICO}/html_chapter/
dico		section	${DICO}/html_section/
dico		node	${DICO}/html_node/

diffutils	mono	${GS}/diffutils/manual/diffutils
diffutils	node	${GS}/diffutils/manual/html_node/

dmd		mono	${GS}/dmd/manual/dmd
dmd		node	${GS}/dmd/manual/html_node/

ed		mono	${GS}/ed/manual/ed_manual.html

EMACS = ${GS}/emacs/manual
emacs		mono	${EMACS}/html_mono/emacs.html
emacs		node	${EMACS}/html_node/emacs/
 #
 ada-mode	mono	${EMACS}/html_mono/ada-mode.html
 ada-mode	node	${EMACS}/html_node/ada-mode/
 #
 autotype	mono	${EMACS}/html_mono/autotype.html
 autotype	node	${EMACS}/html_node/autotype/
 #
 ccmode		mono	${EMACS}/html_mono/ccmode.html
 ccmode		node	${EMACS}/html_node/ccmode/
 #
 cl		mono	${EMACS}/html_mono/cl.html
 cl		node	${EMACS}/html_node/cl/
 #
 ebrowse	mono	${EMACS}/html_mono/ebrowse.html
 ebrowse	node	${EMACS}/html_node/ebrowse/
 #
 ediff		mono	${EMACS}/html_mono/ediff.html
 ediff		node	${EMACS}/html_node/ediff/
 #
 eieio		mono	${EMACS}/html_mono/eieio.html
 eieio		node	${EMACS}/html_node/eieio/
 #
 elisp		mono	${EMACS}/html_mono/elisp.html
 elisp		node	${EMACS}/html_node/elisp/
 #
 epa		mono	${EMACS}/html_mono/epa.html
 epa		node	${EMACS}/html_node/epa/
 #
 erc		mono	${EMACS}/html_mono/erc.html
 erc		node	${EMACS}/html_node/erc/
 #
 dired-x	mono	${EMACS}/html_mono/dired-x.html
 dired-x	node	${EMACS}/html_node/dired-x/
 #
 eshell		mono	${EMACS}/html_mono/eshell.html
 eshell		node	${EMACS}/html_node/eshell/
 #
 eww		mono	${EMACS}/html_mono/eww.html
 eww		node	${EMACS}/html_node/eww/
 #
 flymake	mono	${EMACS}/html_mono/flymake.html
 flymake	node	${EMACS}/html_node/flymake/
 #
 gnus		mono	${EMACS}/html_mono/gnus.html
 gnus		node	${EMACS}/html_node/gnus/
 #
 idlwave	mono	${EMACS}/html_mono/idlwave.html
 idlwave	node	${EMACS}/html_node/idlwave/
 #
 info   	mono	${EMACS}/html_mono/info.html
 info   	node	${EMACS}/html_node/info/
 #
 message	mono	${EMACS}/html_mono/message.html
 message	node	${EMACS}/html_node/message/
 #
 mh-e		mono	${EMACS}/html_mono/mh-e.html
 mh-e		node	${EMACS}/html_node/mh-e/
 #
 nxml-mode	mono	${EMACS}/html_mono/nxml-mode.html
 nxml-mode	node	${EMACS}/html_node/nxml-mode/
 #
 org		mono	${EMACS}/html_mono/org.html
 org		node	${EMACS}/html_node/org/
 #
 pcl-cvs	mono	${EMACS}/html_mono/pcl-cvs.html
 pcl-cvs	node	${EMACS}/html_node/pcl-cvs/
 #
 rcirc		mono	${EMACS}/html_mono/rcirc.html
 rcirc		node	${EMACS}/html_node/rcirc/
 #
 semantic	mono	${EMACS}/html_mono/semantic.html
 semantic	node	${EMACS}/html_node/semantic/
 #
 smtp		mono	${EMACS}/html_mono/smtpmail.html
 smtp		node	${EMACS}/html_node/smtpmail/
 #
 speedbar	mono	${EMACS}/html_mono/speedbar.html
 speedbar	node	${EMACS}/html_node/speedbar/
 #
 tramp		mono	${EMACS}/html_mono/tramp.html
 tramp		node	${EMACS}/html_node/tramp/
 #
 vip		mono	${EMACS}/html_mono/vip.html
 vip		node	${EMACS}/html_node/vip/
 #
 viper		mono	${EMACS}/html_mono/viper.html
 viper		node	${EMACS}/html_node/viper/
 #
 woman		mono	${EMACS}/html_mono/woman.html
 woman		node	${EMACS}/html_node/woman/
 # (end emacs manuals)

easejs		mono	${GS}/easejs/manual/easejs.html
easejs		node	${GS}/easejs/manual/

EMACS_GUIX = https://emacs-guix.gitlab.io/website/manual/latest
emacs-guix	mono	${EMACS_GUIX}/emacs-guix.html
emacs-guix	node	${EMACS_GUIX}/html_node/

emacs-muse	node	${GS}/emacs-muse/manual/muse.html
emacs-muse	node	${GS}/emacs-muse/manual/html_node/

emms		node	${GS}/emms/manual/

# The file is called 'find.info' but the package is 'findutils'.
find		mono	${GS}/findutils/manual/html_mono/find.html
find		node	${GS}/findutils/manual/html_node/find_html
findutils	mono	${GS}/findutils/manual/html_mono/find.html
findutils	node	${GS}/findutils/manual/html_node/find_html

flex		node	https://westes.github.io/flex/manual/

gama		mono	${GS}/gama/manual/gama.html
gama		node	${GS}/gama/manual/html_node/

GAWK = ${GS}/gawk/manual
gawk		mono	${GAWK}/gawk.html
gawk		node	${GAWK}/html_node/
 gawkinet	mono	${GAWK}/gawkinet/gawkinet.html
 gawkinet	node	${GAWK}/gawkinet/html_node/

gcal		mono	${GS}/gcal/manual/gcal.html
gcal		node	${GS}/gcal/manual/html_node/

GCC = https://gcc.gnu.org/onlinedocs
gcc		node	${GCC}/gcc/
 cpp		node	${GCC}/cpp/
 gcj		node	${GCC}/gcj/
 gfortran	node	${GCC}/gfortran/
 gnat_rm	node	${GCC}/gnat_rm/
 gnat_ugn	node	${GCC}/gnat_ugn/
 libgomp	node	${GCC}/libgomp/
 libstdc++	node	${GCC}/libstdc++/
 #
 gccint		node	${GCC}/gccint/
 cppinternals	node	${GCC}/cppinternals/
 gfc-internals	node	${GCC}/gfc-internals/
 gnat-style	node	${GCC}/gnat-style/
 libiberty	node	${GCC}/libiberty/

GDB = https://sourceware.org/gdb/current/onlinedocs
gdb		node	${GDB}/gdb/
 stabs		node	${GDB}/stabs/

GDBM = http://www.gnu.org.ua/software/gdbm/manual
gdbm		mono	${GDBM}/gdbm.html
gdbm		chapter	${GDBM}/html_chapter/
gdbm		section ${GDBM}/html_section/
gdbm		node	${GDBM}/html_node/

geiser		chapter	http://geiser.nongnu.org/

gettext		mono	${GS}/gettext/manual/gettext.html
gettext		node	${GS}/gettext/manual/html_node/

gforth		node	https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/

# Also found at:
# https://mirrors.edge.kernel.org/pub/software/scm/git/docs/user-manual.html
# https://git.github.io/htmldocs/user-manual.html
git		mono	https://git-scm.com/docs/user-manual

global		mono	${GS}/global/manual/global.html

gmediaserver	node	${GS}/gmediaserver/manual/

gmp		node	https://www.gmplib.org/manual/

gnu-arch	node	${GS}/gnu-arch/tutorial/

gnu-c-manual	mono	${GS}/gnu-c-manual/gnu-c-manual.html

gnu-crypto	node	${GS}/gnu-crypto/manual/

gnubg		mono	${GS}/gnubg/manual/gnubg.html
gnubg		node	${GS}/gnubg/manual/html_node/

gnubik		mono	${GS}/gnubik/manual/gnubik.html
gnubik		node	${GS}/gnubik/manual/html_node/

gnulib		mono	${GS}/gnulib/manual/gnulib.html
gnulib		node	${GS}/gnulib/manual/html_node/

GNUN = ${GS}/trans-coord/manual
gnun		mono	${GNUN}/gnun/gnun.html
gnun		node	${GNUN}/gnun/html_node/
 web-trans	mono	${GNUN}/web-trans/web-trans.html
 web-trans	node	${GNUN}/web-trans/html_node/

GNUPG = https://www.gnupg.org/documentation/manuals
gnupg		node	${GNUPG}/gnupg/
 dirmngr	node	${GNUPG}/dirmngr/
 gcrypt		node	${GNUPG}/gcrypt/
 libgcrypt	node	${GNUPG}/gcrypt/
 ksba		node	${GNUPG}/ksba/
 assuan		node	${GNUPG}/assuan/
 gpgme		node	${GNUPG}/gpgme/

gnuprologjava	node	${GS}/gnuprologjava/manual/

gnuschool	mono	${GS}/gnuschool/gnuschool.html

GNUSTANDARDS = ${G}/prep
 maintain	mono	${GNUSTANDARDS}/maintain/maintain.html
 maintain	node	${GNUSTANDARDS}/maintain/html_node/
 #
 standards	mono	${GNUSTANDARDS}/standards/standards.html
 standards	node	${GNUSTANDARDS}/standards/html_node/

gnutls		mono	${GS}/gnutls/manual/gnutls.html
gnutls		node	${GS}/gnutls/manual/html_node/

gnutls-guile	mono	http://gnutls.org/manual/gnutls-guile.html
gnutls-guile	node	http://gnutls.org/manual/gnutls-guile/

gperf		mono	${GS}/gperf/manual/gperf.html
gperf		node	${GS}/gperf/manual/html_node/

grep		mono	${GS}/grep/manual/grep.html
grep		node	${GS}/grep/manual/html_node/

groff		node	${GS}/groff/manual/html_node/

GRUB = ${GS}/grub/manual
  grub		mono	${GRUB}/grub.html
  grub		node	${GRUB}/html_node/
  #
  multiboot	mono	${GRUB}/multiboot/multiboot.html
  multiboot	node	${GRUB}/multiboot/html_node/

gsasl		mono	${GS}/gsasl/manual/gsasl.html
gsasl		node	${GS}/gsasl/manual/html_node/

gsl		node	${GS}/gsl/manual/html_node/

gsrc		mono	${GS}/gsrc/manual/gsrc.html
gsrc		node	${GS}/gsrc/manual/html_node/

gss		mono	${GS}/gss/manual/gss.html
gss		node	${GS}/gss/manual/html_node/

gtypist		mono	${GS}/gtypist/doc/

guile		mono	${GS}/guile/manual/guile.html
guile		node	${GS}/guile/manual/html_node/

guile-avahi	mono	http://nongnu.org/guile-avahi/doc/guile-avahi.html

GUILE_GNOME = ${GS}/guile-gnome/docs
 gobject 	node	${GUILE_GNOME}/gobject/html/
 glib		node	${GUILE_GNOME}/glib/html/
 atk		node	${GUILE_GNOME}/atk/html/
 pango		node	${GUILE_GNOME}/pango/html/
 pangocairo	node	${GUILE_GNOME}/pangocairo/html/
 gdk		node	${GUILE_GNOME}/gdk/html/
 gtk		node	${GUILE_GNOME}/gtk/html/
 libglade	node	${GUILE_GNOME}/libglade/html/
 gnome-vfs	node	${GUILE_GNOME}/gnome-vfs/html/
 libgnomecanvas	node	${GUILE_GNOME}/libgnomecanvas/html/
 gconf		node	${GUILE_GNOME}/gconf/html/
 libgnome	node	${GUILE_GNOME}/libgnome/html/
 libgnomeui	node	${GUILE_GNOME}/libgnomeui/html/
 corba		node	${GUILE_GNOME}/corba/html/
 clutter	node	${GUILE_GNOME}/clutter/html/
 clutter-glx	node	${GUILE_GNOME}/clutter-glx/html/

guile-gtk	node	${GS}/guile-gtk/docs/guile-gtk/

guile-netlink	mono	https://git.lepiller.eu/guile-netlink/manual/manual.html

guile-rpc	mono	${GS}/guile-rpc/manual/guile-rpc.html
guile-rpc	node	${GS}/guile-rpc/manual/html_node/

GUIX_ROOT = https://guix.gnu.org
GUIX = ${GUIX_ROOT}/manual
 guix.de	mono	${GUIX}/de/guix.de.html
 guix.de	node	${GUIX}/de/html_node/
 guix.es	mono	${GUIX}/es/guix.es.html
 guix.es	node	${GUIX}/es/html_node/
 guix.fr	mono	${GUIX}/fr/guix.fr.html
 guix.fr	node	${GUIX}/fr/html_node/
 guix.pt_BR	mono	${GUIX}/pt-br/guix.pt_BR.html
 guix.pt_BR	node	${GUIX}/pt-br/html_node/
 guix.ru	mono	${GUIX}/ru/guix.ru.html
 guix.ru	node	${GUIX}/ru/html_node/
 guix.zh_CN	mono	${GUIX}/zh-cn/guix.zh_CN.html
 guix.zh_CN	node	${GUIX}/zh-cn/html_node/
 guix		mono	${GUIX}/en/guix.html
 guix		node	${GUIX}/en/html_node/

GUIX_COOKBOOK = ${GUIX_ROOT}/cookbook
 guix-cookbook.de	mono	${GUIX_COOKBOOK}/de/guix-cookbook.de.html
 guix-cookbook.de	node    ${GUIX_COOKBOOK}/de/html_node/
 guix-cookbook.fr	mono    ${GUIX_COOKBOOK}/fr/guix-cookbook.fr.html
 guix-cookbook.fr	node    ${GUIX_COOKBOOK}/fr/html_node/
 guix-cookbook.ko	mono    ${GUIX_COOKBOOK}/ko/guix-cookbook.ko.html
 guix-cookbook.ko	node    ${GUIX_COOKBOOK}/ko/html_node/
 guix-cookbook.pt_BR	mono    ${GUIX_COOKBOOK}/pt-br/guix-cookbook.pt_BR.html
 guix-cookbook.pt_BR	node    ${GUIX_COOKBOOK}/pt-br/html_node/
 guix-cookbook.sk	mono    ${GUIX_COOKBOOK}/sk/guix-cookbook.sk.html
 guix-cookbook.sk	node    ${GUIX_COOKBOOK}/sk/html_node/
 guix-cookbook.sv	mono    ${GUIX_COOKBOOK}/sv/guix-cookbook.sv.html
 guix-cookbook.sv	node    ${GUIX_COOKBOOK}/sv/html_node/
 guix-cookbook		mono    ${GUIX_COOKBOOK}/en/guix-cookbook.html
 guix-cookbook		node	${GUIX_COOKBOOK}/en/html_node/

gv		mono	${GS}/gv/manual/gv.html
gv		node	${GS}/gv/manual/html_node/

gzip		mono	${GS}/gzip/manual/gzip.html
gzip		node	${GS}/gzip/manual/html_node/

hello		mono	${GS}/hello/manual/hello.html
hello		node	${GS}/hello/manual/html_node/

help2man	mono	${GS}/help2man/help2man.html

# XXX: These are actually pages created by texi2html, so no quite following
# the expected naming scheme.
hurd		mono	${GS}/hurd/doc/

idutils		mono	${GS}/idutils/manual/idutils.html
idutils		node	${GS}/idutils/manual/html_node/

inetutils	mono	${GS}/inetutils/manual/inetutils.html
inetutils	node	${GS}/inetutils/manual/html_node/

jwhois		mono	${GS}/jwhois/manual/jwhois.html
jwhois		node	${GS}/jwhois/manual/html_node/

libc		mono	${GS}/libc/manual/html_mono/libc.html
libc		node	${GS}/libc/manual/html_node/

LIBCDIO = ${GS}/libcdio
 libcdio	mono	${LIBCDIO}/libcdio.html
 cd-text	mono	${LIBCDIO}/cd-text-format.html

libextractor	mono	${GS}/libextractor/manual/libextractor.html
libextractor	node	${GS}/libextractor/manual/html_node/

libidn		mono	${GS}/libidn/manual/libidn.html
libidn		node	${GS}/libidn/manual/html_node/

librejs		mono	${GS}/librejs/manual/librejs.html
librejs		node	${GS}/librejs/manual/html_node/

libmatheval	mono	${GS}/libmatheval/manual/libmatheval.html

LIBMICROHTTPD = ${GS}/libmicrohttpd
libmicrohttpd		mono	${LIBMICROHTTPD}/manual/libmicrohttpd.html
libmicrohttpd		node	${LIBMICROHTTPD}/manual/html_node/
 microhttpd-tutorial	mono	${LIBMICROHTTPD}/tutorial.html

libtasn1	mono	${GS}/libtasn1/manual/libtasn1.html
libtasn1	node	${GS}/libtasn1/manual/html_node/

libtool		mono	${GS}/libtool/manual/libtool.html
libtool		node	${GS}/libtool/manual/html_node/

lightning	mono	${GS}/lightning/manual/lightning.html
lightning	node	${GS}/lightning/manual/html_node/

# The stable/ url redirects immediately, but that's ok.
# The .html extension is omitted on their web site, but it works if given.
LILYPOND = http://lilypond.org/doc/stable/Documentation
 lilypond-internals	node ${LILYPOND}/internals/
 lilypond-learning	node ${LILYPOND}/learning/
 lilypond-notation 	node ${LILYPOND}/notation/
 lilypond-snippets 	node ${LILYPOND}/snippets/
 lilypond-usage		node ${LILYPOND}/usage/
 lilypond-web		node ${LILYPOND}/web/
 music-glossary		node ${LILYPOND}/music-glossary/

liquidwar6	mono	${GS}/liquidwar6/manual/liquidwar6.html
liquidwar6	node	${GS}/liquidwar6/manual/html_node/

lispintro	mono	${GS}/emacs/emacs-lisp-intro/html_mono/emacs-lisp-intro.html
lispintro	node	${GS}/emacs/emacs-lisp-intro/html_node/index.html

LSH = http://www.lysator.liu.se/~nisse/lsh
  lsh		mono	${LSH}/lsh.html

m4		mono	${GS}/m4/manual/m4.html
m4		node	${GS}/m4/manual/html_node/

mailutils	mono	${GS}/mailutils/manual/mailutils.html
mailutils	chapter	${GS}/mailutils/manual/html_chapter/
mailutils	section	${GS}/mailutils/manual/html_section/
mailutils	node	${GS}/mailutils/manual/html_node/

make		mono	${GS}/make/manual/make.html
make		node	${GS}/make/manual/html_node/

mcron		mono	${GS}/mcron/manual/mcron.html
mcron		node	${GS}/mcron/manual/html_node/

mdk		mono	${GS}/mdk/manual/mdk.html
mdk		node	${GS}/mdk/manual/html_node/

METAEXCHANGE = https://ftp.gwdg.de/pub/gnu2/iwfmdh/doc/texinfo
 iwf_mh		node	${METAEXCHANGE}/iwf_mh.html
 scantest	node	${METAEXCHANGE}/scantest.html

mes		mono	${GS}/mes/manual/mes.html
mes		node	${GS}/mes/manual/html_node/

MIT_SCHEME = ${GS}/mit-scheme/documentation/stable
 mit-scheme-ref	  mono	${MIT_SCHEME}/mit-scheme-ref.html
 mit-scheme-ref	  node	${MIT_SCHEME}/mit-scheme-ref/
 mit-scheme-user  mono	${MIT_SCHEME}/mit-scheme-user.html
 mit-scheme-user  node	${MIT_SCHEME}/mit-scheme-user/
 sos		  mono	${MIT_SCHEME}/mit-scheme-sos.html
 sos		  node	${MIT_SCHEME}/mit-scheme-sos/
 mit-scheme-imail mono	${MIT_SCHEME}/mit-scheme-imail.html

moe		mono	${GS}/moe/manual/moe_manual.html

motti		node	${GS}/motti/manual/

mpc		node	http://www.multiprecision.org/index.php?prog=mpc&page=html

mpfr		mono	http://www.mpfr.org/mpfr-current/mpfr.html

mtools		mono	${GS}/mtools/manual/mtools.html

myserver	mono	http://www.myserverproject.net/doc.php

nano		mono	https://www.nano-editor.org/dist/latest/nano.html

nettle		chapter	http://www.lysator.liu.se/~nisse/nettle/nettle.html

ocrad		mono	${GS}/ocrad/manual/ocrad_manual.html

parted		mono	${GS}/parted/manual/parted.html
parted		node	${GS}/parted/manual/html_node/

pascal		mono	http://www.gnu-pascal.de/gpc/

# can't use pcb since url's contain dates --30nov10

perl		mono	${GS}/perl/manual/perldoc-all.html

PIES = http://www.gnu.org.ua/software/pies/manual
pies		mono	${PIES}/pies.html
pies 		chapter	${PIES}/html_chapter/
pies 		section	${PIES}/html_section/
pies		node	${PIES}/html_node/

plotutils	mono	${GS}/plotutils/manual/en/plotutils.html
plotutils	node	${GS}/plotutils/manual/en/html_node/

proxyknife	mono	${GS}/proxyknife/manual/proxyknife.html
proxyknife	node	${GS}/proxyknife/manual/html_node/

pspp		mono	${GS}/pspp/manual/pspp.html
pspp		node	${GS}/pspp/manual/html_node/

pyconfigure	mono	${GS}/pyconfigure/manual/pyconfigure.html
pyconfigure	node	${GS}/pyconfigure/manual/html_node/

R = https://cran.r-project.org/doc/manuals
 R-intro	mono	${R}/R-intro.html
 R-lang		mono	${R}/R-lang.html
 R-exts		mono	${R}/R-exts.html
 R-data		mono	${R}/R-data.html
 R-admin	mono	${R}/R-admin.html
 R-ints		mono	${R}/R-ints.html

rcs		mono	${GS}/rcs/manual/rcs.html
rcs		node	${GS}/rcs/manual/html_node/

READLINE = https://tiswww.cwru.edu/php/chet/readline
readline        mono    ${READLINE}/readline.html
 rluserman      mono    ${READLINE}/rluserman.html
 history        mono    ${READLINE}/history.html

recode		mono	http://recode.progiciels-bpi.ca/manual/index.html

recutils	mono	${GS}/recutils/manual/recutils.html
recutils	node	${GS}/recutils/manual/html_node/

reftex		mono	${GS}/auctex/manual/reftex.html
reftex		node	${GS}/auctex/manual/reftex/

remotecontrol	mono	${GS}/remotecontrol/manual/remotecontrol.html
remotecontrol	node	${GS}/remotecontrol/manual/html_node/

rottlog		mono	${GS}/rottlog/manual/rottlog.html
rottlog		node	${GS}/rottlog/manual/html_node/

RUSH = http://www.gnu.org.ua/software/rush/manual
rush		mono	${RUSH}/rush.html
rush 		chapter	${RUSH}/html_chapter/
rush 		section	${RUSH}/html_section/
rush		node	${RUSH}/html_node/

screen		mono	${GS}/screen/manual/screen.html
screen		node	${GS}/screen/manual/html_node/

sed		mono	${GS}/sed/manual/sed.html
sed		node	${GS}/sed/manual/html_node/

sharutils	mono	${GS}/sharutils/manual/html_mono/sharutils.html
sharutils	chapter	${GS}/sharutils/manual/html_chapter/
sharutils	node	${GS}/sharutils/manual/html_node/

shepherd	mono	${GS}/shepherd/manual/shepherd.html
shepherd	node	${GS}/shepherd/manual/html_node/

# can't use mono files since they have generic names
SMALLTALK = ${GS}/smalltalk
smalltalk	node	${SMALLTALK}/manual/html_node/
 smalltalk-base	node	${SMALLTALK}/manual-base/html_node/
 smalltalk-libs	node	${SMALLTALK}/manual-libs/html_node/

sourceinstall	mono	${GS}/sourceinstall/manual/sourceinstall.html
sourceinstall	node	${GS}/sourceinstall/manual/html_node/

sqltutor	mono	${GS}/sqltutor/manual/sqltutor.html
sqltutor	node	${GS}/sqltutor/manual/html_node/

src-highlite	mono	${GS}/src-highlite/source-highlight.html

swbis		mono	${GS}/swbis/manual.html

tar		mono	${GS}/tar/manual/tar.html
tar		chapter	${GS}/tar/manual/html_chapter/
tar		section	${GS}/tar/manual/html_section/
tar		node	${GS}/tar/manual/html_node/

teseq		mono	${GS}/teseq/teseq.html
teseq		node	${GS}/teseq/html_node/

TEXINFO = ${GS}/texinfo/manual
texinfo		mono	${TEXINFO}/texinfo/texinfo.html
texinfo		node	${TEXINFO}/texinfo/html_node/
 #
 info-stnd	mono	${TEXINFO}/info-stnd/info-stnd.html
 info-stnd	node	${TEXINFO}/info-stnd/html_node/

thales		node	${GS}/thales/manual/

units		mono	${GS}/units/manual/units.html
units		node	${GS}/units/manual/html_node/

vc-dwim		mono	${GS}/vc-dwim/manual/vc-dwim.html
vc-dwim		node	${GS}/vc-dwim/manual/html_node/

wdiff		mono	${GS}/wdiff/manual/wdiff.html
wdiff		node	${GS}/wdiff/manual/html_node/

websocket4j	mono	${GS}/websocket4j/manual/websocket4j.html
websocket4j	node	${GS}/websocket4j/manual/html_node/

wget		mono	${GS}/wget/manual/wget.html
wget		node	${GS}/wget/manual/html_node/

xboard		mono	${GS}/xboard/manual/xboard.html
xboard		node	${GS}/xboard/manual/html_node/

# emacs-page
# Free TeX-related Texinfo manuals on tug.org.

T = https://tug.org/texinfohtml

dvipng		mono	${T}/dvipng.html
dvips		mono	${T}/dvips.html
eplain		mono	${T}/eplain.html
kpathsea	mono	${T}/kpathsea.html
latex2e		mono	${T}/latex2e.html
tlbuild		mono	${T}/tlbuild.html
web2c		mono	${T}/web2c.html


# Local Variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "htmlxrefversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
garbage? (string-contains (with-fluids ((%default-port-encoding "UTF-8")) ;for the string port (call-with-output-string (lambda (port) (parameterize ((current-build-output-port port)) (let ((d (build-expression->derivation %store "foo" `(begin (use-modules (rnrs io ports)) (display "garbage: ") (put-bytevector (current-output-port) #vu8(128)) (display "lambda: λ\n")) #:guile-for-build (package-derivation %store %bootstrap-guile)))) (guard (c ((store-protocol-error? c) #t)) (build-derivations %store (list d)))))))) "garbage: �lambda: λ")) (test-assert "log-file, derivation" (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '())) (s (add-to-store %store "bash" #t "sha256" (search-bootstrap-binary "bash" (%current-system)))) (d (derivation %store "the-thing" s `("-e" ,b) #:env-vars `(("foo" . ,(random-text))) #:inputs `((,b) (,s))))) (and (build-derivations %store (list d)) (file-exists? (pk (log-file %store (derivation-file-name d))))))) (test-assert "log-file, output file name" (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '())) (s (add-to-store %store "bash" #t "sha256" (search-bootstrap-binary "bash" (%current-system)))) (d (derivation %store "the-thing" s `("-e" ,b) #:env-vars `(("foo" . ,(random-text))) #:inputs `((,b) (,s)))) (o (derivation->output-path d))) (and (build-derivations %store (list d)) (file-exists? (pk (log-file %store o))) (string=? (log-file %store (derivation-file-name d)) (log-file %store o))))) (test-assert "no substitutes" (with-store s (let* ((d1 (package-derivation s %bootstrap-guile (%current-system))) (d2 (package-derivation s %bootstrap-glibc (%current-system))) (o (map derivation->output-path (list d1 d2)))) (set-build-options s #:use-substitutes? #f) (and (not (has-substitutes? s (derivation-file-name d1))) (not (has-substitutes? s (derivation-file-name d2))) (null? (substitutable-paths s o)) (null? (substitutable-path-info s o)))))) (test-assert "build-things with output path" (with-store s (let* ((c (random-text)) ;contents of the output (d (build-expression->derivation s "substitute-me" `(call-with-output-file %output (lambda (p) (display ,c p))) #:guile-for-build (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) (set-build-options s #:use-substitutes? #f) ;; Pass 'build-things' the output file name, O. However, since there ;; are no substitutes for O, it will just do nothing. (build-things s (list o)) (not (valid-path? s o))))) (test-skip (if (getenv "GUIX_BINARY_SUBSTITUTE_URL") 0 1)) (test-assert "substitute query" (with-store s (let* ((d (package-derivation s %bootstrap-guile (%current-system))) (o (derivation->output-path d))) ;; Create fake substituter data, to be read by 'guix substitute'. (with-derivation-narinfo d ;; Remove entry from the local cache. (false-if-exception (delete-file-recursively (string-append (getenv "XDG_CACHE_HOME") "/guix/substitute"))) ;; Make sure 'guix substitute' correctly communicates the above ;; data. (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (equal? (list o) (substitutable-paths s (list o))) (match (pk 'spi (substitutable-path-info s (list o))) (((? substitutable? s)) (and (string=? (substitutable-deriver s) (derivation-file-name d)) (null? (substitutable-references s)) (equal? (substitutable-nar-size s) 1234))))))))) (test-assert "substitute query, alternating URLs" (let* ((d (with-store s (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) (with-derivation-narinfo d ;; Remove entry from the local cache. (false-if-exception (delete-file-recursively (string-append (getenv "XDG_CACHE_HOME") "/guix/substitute"))) ;; Note: We reconnect to the daemon to force a new instance of 'guix ;; substitute' to be used; otherwise the #:substitute-urls of ;; 'set-build-options' would have no effect. (and (with-store s ;the right substitute URL (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (has-substitutes? s o)) (with-store s ;the wrong one (set-build-options s #:use-substitutes? #t #:substitute-urls (list "http://does-not-exist")) (not (has-substitutes? s o))) (with-store s ;the right one again (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (has-substitutes? s o)) (with-store s ;empty list of URLs (set-build-options s #:use-substitutes? #t #:substitute-urls '()) (not (has-substitutes? s o))))))) (test-assert "substitute" (with-store s (let* ((c (random-text)) ; contents of the output (d (build-expression->derivation s "substitute-me" `(call-with-output-file %output (lambda (p) (exit 1) ; would actually fail (display ,c p))) #:guile-for-build (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) (with-derivation-substitute d c (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (build-derivations s (list d)) (canonical-file? o) (equal? c (call-with-input-file o get-string-all))))))) (test-assert "substitute, deduplication" (with-store s ;; Note: C must be longer than %DEDUPLICATION-MINIMUM-SIZE. (let* ((c (string-concatenate (make-list 200 (random-text)))) ; contents of the output (g (package-derivation s %bootstrap-guile)) (d1 (build-expression->derivation s "substitute-me" `(begin ,c (exit 1)) #:guile-for-build g)) (d2 (build-expression->derivation s "build-me" `(call-with-output-file %output (lambda (p) (display ,c p))) #:guile-for-build g)) (o1 (derivation->output-path d1)) (o2 (derivation->output-path d2))) (with-derivation-substitute d1 c (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o1) (build-derivations s (list d2)) ;build (build-derivations s (list d1)) ;substitute (canonical-file? o1) (equal? c (call-with-input-file o1 get-string-all)) (= (stat:ino (stat o1)) (stat:ino (stat o2)))))))) (test-assert "substitute + build-things with output path" (with-store s (let* ((c (random-text)) ;contents of the output (d (build-expression->derivation s "substitute-me" `(call-with-output-file %output (lambda (p) (exit 1) ;would actually fail (display ,c p))) #:guile-for-build (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) (with-derivation-substitute d c (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (build-things s (list o)) ;give the output path (valid-path? s o) (canonical-file? o) (equal? c (call-with-input-file o get-string-all))))))) (test-assert "substitute + build-things with specific output" (with-store s (let* ((c (random-text)) ;contents of the output (d (build-expression->derivation s "substitute-me" `(begin ,c (exit 1)) ;would fail #:outputs '("out" "one" "two") #:guile-for-build (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) (with-derivation-substitute d c (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) ;; Ask for nothing but the "out" output of D. (build-things s `((,(derivation-file-name d) . "out"))) (valid-path? s o) (canonical-file? o) (equal? c (call-with-input-file o get-string-all))))))) (test-assert "substitute, corrupt output hash" ;; Tweak the substituter into installing a substitute whose hash doesn't ;; match the one announced in the narinfo. The daemon must notice this and ;; raise an error. (with-store s (let* ((c "hello, world") ; contents of the output (d (build-expression->derivation s "corrupt-substitute" `(mkdir %output) #:guile-for-build (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) (with-derivation-substitute d c (sha256 => (make-bytevector 32 0)) ;select a hash that doesn't match C ;; Make sure we use 'guix substitute'. (set-build-options s #:use-substitutes? #t #:fallback? #f #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (guard (c ((store-protocol-error? c) ;; XXX: the daemon writes "hash mismatch in downloaded ;; path", but the actual error returned to the client ;; doesn't mention that. (pk 'corrupt c) (not (zero? (store-protocol-error-status c))))) (build-derivations s (list d)) #f)))))) (test-assert "substitute, corrupt output hash, build trace" ;; Likewise, and check the build trace. (with-store s (let* ((c "hello, world") ; contents of the output (d (build-expression->derivation s "corrupt-substitute" `(mkdir %output) #:guile-for-build (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) ;; Make sure we use 'guix substitute'. (set-build-options s #:print-build-trace #t #:use-substitutes? #t #:fallback? #f #:substitute-urls (%test-substitute-urls)) (with-derivation-substitute d c (sha256 => (make-bytevector 32 0)) ;select a hash that doesn't match C (define output (call-with-output-string (lambda (port) (parameterize ((current-build-output-port port)) (guard (c ((store-protocol-error? c) #t)) (build-derivations s (list d)) #f))))) (define actual-hash (let-values (((port get-hash) (gcrypt:open-hash-port (gcrypt:hash-algorithm gcrypt:sha256)))) (write-file-tree "foo" port #:file-type+size (lambda _ (values 'regular (string-length c))) #:file-port (lambda _ (open-input-string c))) (close-port port) (bytevector->nix-base32-string (get-hash)))) (define expected-hash (bytevector->nix-base32-string (make-bytevector 32 0))) (define mismatch (string-append "@ hash-mismatch " o " sha256 " expected-hash " " actual-hash "\n")) (define failure (string-append "@ substituter-failed " o)) (and (string-contains output mismatch) (string-contains output failure)))))) (test-assert "substitute --fallback" (with-store s (let* ((t (random-text)) ; contents of the output (d (build-expression->derivation s "substitute-me-not" `(call-with-output-file %output (lambda (p) (display ,t p))) #:guile-for-build (package-derivation s %bootstrap-guile (%current-system)))) (o (derivation->output-path d))) ;; Create fake substituter data, to be read by 'guix substitute'. (with-derivation-narinfo d ;; Make sure we use 'guix substitute'. (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (and (has-substitutes? s o) (guard (c ((store-protocol-error? c) ;; The substituter failed as expected. Now make ;; sure that #:fallback? #t works correctly. (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls) #:fallback? #t) (and (build-derivations s (list d)) (equal? t (call-with-input-file o get-string-all))))) ;; Should fail. (build-derivations s (list d)) #f)))))) (test-equal "substitute query and large size" (+ 100 (expt 2 63)) ; (with-store s (let* ((size (+ 100 (expt 2 63))) ;does not fit in signed 'long long' (item (string-append (%store-prefix) "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bad-size"))) ;; Create fake substituter data, to be read by 'guix substitute'. (call-with-output-file (string-append (%substitute-directory) "/" (store-path-hash-part item) ".narinfo") (lambda (port) (format port "StorePath: ~a URL: http://example.org Compression: none NarSize: ~a NarHash: sha256:0fj9vhblff2997pi7qjj7lhmy7wzhnjwmkm2hmq6gr4fzmg10s0w References: System: x86_64-linux~%" item size))) ;; Remove entry from the local cache. (false-if-exception (delete-file-recursively (string-append (getenv "XDG_CACHE_HOME") "/guix/substitute"))) ;; Make sure 'guix substitute' correctly communicates the above ;; data. (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (match (pk 'spi (substitutable-path-info s (list item))) (((? substitutable? s)) (and (equal? (substitutable-path s) item) (substitutable-nar-size s))))))) (test-equal "substitute and large size" (+ 100 (expt 2 31)) ; (with-store s (let* ((size (+ 100 (expt 2 31))) ;does not fit in signed 'int' (item (string-append (%store-prefix) "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bad-size-" (random-text))) (nar (string-append (%substitute-directory) "/nar"))) ;; Create a dummy nar to allow for substitution. (call-with-output-file nar (lambda (port) (write-file-tree (store-path-package-name item) port #:file-type+size (lambda _ (values 'regular 12)) #:file-port (lambda _ (open-input-string "Hello world."))))) ;; Create fake substituter data, to be read by 'guix substitute'. (call-with-output-file (string-append (%substitute-directory) "/" (store-path-hash-part item) ".narinfo") (lambda (port) (format port "StorePath: ~a URL: file://~a Compression: none NarSize: ~a NarHash: sha256:~a References: System: x86_64-linux~%" item nar size (bytevector->nix-base32-string (gcrypt:file-sha256 nar))))) ;; Remove entry from the local cache. (false-if-exception (delete-file-recursively (string-append (getenv "XDG_CACHE_HOME") "/guix/substitute"))) ;; Make sure 'guix substitute' correctly communicates the above ;; data. (set-build-options s #:use-substitutes? #t #:substitute-urls (%test-substitute-urls)) (ensure-path s item) (path-info-nar-size (query-path-info s item))))) (test-assert "export/import several paths" (let* ((texts (unfold (cut >= <> 10) (lambda _ (random-text)) 1+ 0)) (files (map (cut add-text-to-store %store "text" <>) texts)) (dump (call-with-bytevector-output-port (cut export-paths %store files <>)))) (delete-paths %store files) (and (every (negate file-exists?) files) (let* ((source (open-bytevector-input-port dump)) (imported (import-paths %store source))) (and (equal? imported files) (every file-exists? files) (equal? texts (map (lambda (file) (call-with-input-file file get-string-all)) files))))))) (test-assert "export/import paths, ensure topological order" (let* ((file0 (add-text-to-store %store "baz" (random-text))) (file1 (add-text-to-store %store "foo" (random-text) (list file0))) (file2 (add-text-to-store %store "bar" (random-text) (list file1))) (files (list file1 file2)) (dump1 (call-with-bytevector-output-port (cute export-paths %store (list file1 file2) <>))) (dump2 (call-with-bytevector-output-port (cute export-paths %store (list file2 file1) <>)))) (delete-paths %store files) (and (every (negate file-exists?) files) (bytevector=? dump1 dump2) (let* ((source (open-bytevector-input-port dump1)) (imported (import-paths %store source))) ;; DUMP1 should contain exactly FILE1 and FILE2, not FILE0. (and (equal? imported (list file1 file2)) (every file-exists? files) (equal? (list file0) (references %store file1)) (equal? (list file1) (references %store file2))))))) (test-assert "export/import incomplete" (let* ((file0 (add-text-to-store %store "baz" (random-text))) (file1 (add-text-to-store %store "foo" (random-text) (list file0))) (file2 (add-text-to-store %store "bar" (random-text) (list file1))) (dump (call-with-bytevector-output-port (cute export-paths %store (list file2) <>)))) (delete-paths %store (list file0 file1 file2)) (guard (c ((store-protocol-error? c) (and (not (zero? (store-protocol-error-status c))) (string-contains (store-protocol-error-message c) "not valid")))) ;; Here we get an exception because DUMP does not include FILE0 and ;; FILE1, which are dependencies of FILE2. (import-paths %store (open-bytevector-input-port dump))))) (test-assert "export/import recursive" (let* ((file0 (add-text-to-store %store "baz" (random-text))) (file1 (add-text-to-store %store "foo" (random-text) (list file0))) (file2 (add-text-to-store %store "bar" (random-text) (list file1))) (dump (call-with-bytevector-output-port (cute export-paths %store (list file2) <> #:recursive? #t)))) (delete-paths %store (list file0 file1 file2)) (let ((imported (import-paths %store (open-bytevector-input-port dump)))) (and (equal? imported (list file0 file1 file2)) (every file-exists? (list file0 file1 file2)) (equal? (list file0) (references %store file1)) (equal? (list file1) (references %store file2)))))) (test-assert "write-file & export-path yield the same result" ;; Here we compare 'write-file' and the daemon's own implementation. ;; 'write-file' is the reference because we know it sorts file ;; deterministically. Conversely, the daemon uses 'readdir' and the entries ;; currently happen to be sorted as a side-effect of some unrelated ;; operation (search for 'unhacked' in archive.cc.) Make sure we detect any ;; changes there. (run-with-store %store (mlet* %store-monad ((drv1 (package->derivation %bootstrap-guile)) (out1 -> (derivation->output-path drv1)) (data -> (unfold (cut >= <> 26) (lambda (i) (random-bytevector 128)) 1+ 0)) (build -> #~(begin (use-modules (rnrs io ports) (srfi srfi-1)) (let () (define letters (map (lambda (i) (string (integer->char (+ i (char->integer #\a))))) (iota 26))) (define (touch file data) (call-with-output-file file (lambda (port) (put-bytevector port data)))) (mkdir #$output) (chdir #$output) ;; The files must be different so they have ;; different inode numbers, and the inode ;; order must differ from the lexicographic ;; order. (for-each touch (append (drop letters 10) (take letters 10)) (list #$@data)) #t))) (drv2 (gexp->derivation "bunch" build)) (out2 -> (derivation->output-path drv2)) (item-info -> (store-lift query-path-info))) (mbegin %store-monad (built-derivations (list drv1 drv2)) (foldm %store-monad (lambda (item result) (define ref-hash (let-values (((port get) (gcrypt:open-sha256-port))) (write-file item port) (close-port port) (get))) ;; 'query-path-info' returns a hash produced by using the ;; daemon's C++ 'dump' function, which is the implementation ;; under test. (>>= (item-info item) (lambda (info) (return (and result (bytevector=? (path-info-hash info) ref-hash)))))) #t (list out1 out2)))) #:guile-for-build (%guile-for-build))) (test-assert "import not signed" (let* ((text (random-text)) (file (add-file-tree-to-store %store `("tree" directory ("text" regular (data ,text)) ("link" symlink "text")))) (dump (call-with-bytevector-output-port (lambda (port) (write-int 1 port) ;start (write-file file port) ;contents (write-int #x4558494e port) ;%export-magic (write-string file port) ;store item (write-string-list '() port) ;references (write-string "" port) ;deriver (write-int 0 port) ;not signed (write-int 0 port))))) ;done ;; Ensure 'import-paths' raises an exception. (guard (c ((store-protocol-error? c) (and (not (zero? (store-protocol-error-status c))) (string-contains (store-protocol-error-message c) "lacks a signature")))) (let* ((source (open-bytevector-input-port dump)) (imported (import-paths %store source))) (pk 'unsigned-imported imported) #f)))) (test-assert "import signed by unauthorized key" (let* ((text (random-text)) (file (add-file-tree-to-store %store `("tree" directory ("text" regular (data ,text)) ("link" symlink "text")))) (key (gcrypt:generate-key (gcrypt:string->canonical-sexp "(genkey (ecdsa (curve Ed25519) (flags rfc6979)))"))) (dump (call-with-bytevector-output-port (lambda (port) (write-int 1 port) ;start (write-file file port) ;contents (write-int #x4558494e port) ;%export-magic (write-string file port) ;store item (write-string-list '() port) ;references (write-string "" port) ;deriver (write-int 1 port) ;signed (write-string (gcrypt:canonical-sexp->string (signature-sexp (gcrypt:bytevector->hash-data (gcrypt:sha256 #vu8(0 1 2)) #:key-type 'ecc) (gcrypt:find-sexp-token key 'private-key) (gcrypt:find-sexp-token key 'public-key))) port) (write-int 0 port))))) ;done ;; Ensure 'import-paths' raises an exception. (guard (c ((store-protocol-error? c) (and (not (zero? (store-protocol-error-status c))) (string-contains (store-protocol-error-message c) "unauthorized public key")))) (let* ((source (open-bytevector-input-port dump)) (imported (import-paths %store source))) (pk 'unauthorized-imported imported) #f)))) (test-assert "import corrupt path" (let* ((text (random-text)) (file (add-text-to-store %store "text" text)) (dump (call-with-bytevector-output-port (cut export-paths %store (list file) <>)))) (delete-paths %store (list file)) ;; Flip a bit in the stream's payload. INDEX here falls in the middle of ;; the file contents in DUMP, regardless of the store prefix. (let* ((index #x70) (byte (bytevector-u8-ref dump index))) (bytevector-u8-set! dump index (logxor #xff byte))) (and (not (file-exists? file)) (guard (c ((store-protocol-error? c) (pk 'c c) (and (not (zero? (store-protocol-error-status c))) (string-contains (store-protocol-error-message c) "corrupt")))) (let* ((source (open-bytevector-input-port dump)) (imported (import-paths %store source))) (pk 'corrupt-imported imported) #f))))) (test-assert "verify-store" (let* ((text (random-text)) (file1 (add-text-to-store %store "foo" text)) (file2 (add-text-to-store %store "bar" (random-text) (list file1)))) (and (pk 'verify1 (verify-store %store)) ;hopefully OK ; (begin (delete-file file1) (not (pk 'verify2 (verify-store %store)))) ;bad! ; (begin ;; Using 'add-text-to-store' here wouldn't work: It would succeed ; ;; without actually creating the file. ; (call-with-output-file file1 (lambda (port) (display text port))) (pk 'verify3 (verify-store %store)))))) ;OK again (test-assert "verify-store + check-contents" ;; XXX: This test is I/O intensive. (with-store s (let* ((text (random-text)) (drv (build-expression->derivation s "corrupt" `(let ((out (assoc-ref %outputs "out"))) (call-with-output-file out (lambda (port) (display ,text port))) #t) #:guile-for-build (package-derivation s %bootstrap-guile (%current-system)))) (file (derivation->output-path drv))) (with-derivation-substitute drv text (and (build-derivations s (list drv)) (verify-store s #:check-contents? #t) ;should be OK (begin (chmod file #o644) (call-with-output-file file (lambda (port) (display "corrupt!" port))) #t) ;; Make sure the corruption is detected. We don't test repairing ;; because only "trusted" users are allowed to do it, but we ;; don't expose that notion of trusted users that nix-daemon ;; supports because it seems dubious and redundant with what the ;; OS provides (in Nix "trusted" users have additional ;; privileges, such as overriding the set of substitute URLs, but ;; we instead want to allow anyone to modify them, provided ;; substitutes are signed by a root-approved key.) (not (verify-store s #:check-contents? #t)) ;; Delete the corrupt item to leave the store in a clean state. (delete-paths s (list file))))))) (test-assert "build-things, check mode" (with-store store (call-with-temporary-output-file (lambda (entropy entropy-port) (write (random-text) entropy-port) (force-output entropy-port) (let* ((drv (build-expression->derivation store "non-deterministic" `(begin (use-modules (rnrs io ports)) (let ((out (assoc-ref %outputs "out"))) (call-with-output-file out (lambda (port) ;; Rely on the fact that tests do not use the ;; chroot, and thus ENTROPY is readable. (display (call-with-input-file ,entropy get-string-all) port))) #t)) #:guile-for-build (package-derivation store %bootstrap-guile (%current-system)))) (file (derivation->output-path drv))) (and (build-things store (list (derivation-file-name drv))) (begin (write (random-text) entropy-port) (force-output entropy-port) (guard (c ((store-protocol-error? c) (pk 'determinism-exception c) (and (not (zero? (store-protocol-error-status c))) (string-contains (store-protocol-error-message c) "deterministic")))) ;; This one will produce a different result. Since we're in ;; 'check' mode, this must fail. (build-things store (list (derivation-file-name drv)) (build-mode check)) #f)))))))) (test-assert "build-succeeded trace in check mode" (string-contains (call-with-output-string (lambda (port) (let ((d (build-expression->derivation %store "foo" '(mkdir (assoc-ref %outputs "out")) #:guile-for-build (package-derivation %store %bootstrap-guile)))) (build-derivations %store (list d)) (parameterize ((current-build-output-port port)) (build-derivations %store (list d) (build-mode check)))))) "@ build-succeeded")) (test-assert "build multiple times" (with-store store ;; Ask to build twice. (set-build-options store #:rounds 2 #:use-substitutes? #f) (call-with-temporary-output-file (lambda (entropy entropy-port) (write (random-text) entropy-port) (force-output entropy-port) (let* ((drv (build-expression->derivation store "non-deterministic" `(begin (use-modules (rnrs io ports)) (let ((out (assoc-ref %outputs "out"))) (call-with-output-file out (lambda (port) ;; Rely on the fact that tests do not use the ;; chroot, and thus ENTROPY is accessible. (display (call-with-input-file ,entropy get-string-all) port) (call-with-output-file ,entropy (lambda (port) (write 'foobar port))))) #t)) #:guile-for-build (package-derivation store %bootstrap-guile (%current-system)))) (file (derivation->output-path drv))) (guard (c ((store-protocol-error? c) (pk 'multiple-build c) (and (not (zero? (store-protocol-error-status c))) (string-contains (store-protocol-error-message c) "deterministic")))) ;; This one will produce a different result on the second run. (current-build-output-port (current-error-port)) (build-things store (list (derivation-file-name drv))) #f)))))) (test-equal "store-lower" "Lowered." (let* ((add (store-lower text-file)) (file (add %store "foo" "Lowered."))) (call-with-input-file file get-string-all))) (test-equal "current-system" "bar" (parameterize ((%current-system "frob")) (run-with-store %store (mbegin %store-monad (set-current-system "bar") (current-system)) #:system "foo"))) (test-assert "query-path-info" (let* ((ref (add-text-to-store %store "ref" "foo")) (item (add-text-to-store %store "item" "bar" (list ref))) (info (query-path-info %store item))) (and (equal? (path-info-references info) (list ref)) (equal? (path-info-hash info) (gcrypt:sha256 (string->utf8 (call-with-output-string (cut write-file item <>)))))))) (test-assert "path-info-deriver" (let* ((b (add-text-to-store %store "build" "echo $foo > $out" '())) (s (add-to-store %store "bash" #t "sha256" (search-bootstrap-binary "bash" (%current-system)))) (d (derivation %store "the-thing" s `("-e" ,b) #:env-vars `(("foo" . ,(random-text))) #:inputs `((,b) (,s)))) (o (derivation->output-path d))) (and (build-derivations %store (list d)) (not (path-info-deriver (query-path-info %store b))) (string=? (derivation-file-name d) (path-info-deriver (query-path-info %store o)))))) (test-equal "build-cores" (list 0 42) (with-store store (let* ((build (add-text-to-store store "build.sh" "echo $NIX_BUILD_CORES > $out")) (bash (add-to-store store "bash" #t "sha256" (search-bootstrap-binary "bash" (%current-system)))) (drv1 (derivation store "the-thing" bash `("-e" ,build) #:inputs `((,bash) (,build)) #:env-vars `(("x" . ,(random-text))))) (drv2 (derivation store "the-thing" bash `("-e" ,build) #:inputs `((,bash) (,build)) #:env-vars `(("x" . ,(random-text)))))) (and (build-derivations store (list drv1)) (begin (set-build-options store #:build-cores 42) (build-derivations store (list drv2))) (list (call-with-input-file (derivation->output-path drv1) read) (call-with-input-file (derivation->output-path drv2) read)))))) (test-equal "multiplexed-build-output" '("Hello from first." "Hello from second.") (with-store store (let* ((build (add-text-to-store store "build.sh" "echo Hello from $NAME.; echo > $out")) (bash (add-to-store store "bash" #t "sha256" (search-bootstrap-binary "bash" (%current-system)))) (drv1 (derivation store "one" bash `("-e" ,build) #:inputs `((,bash) (,build)) #:env-vars `(("NAME" . "first") ("x" . ,(random-text))))) (drv2 (derivation store "two" bash `("-e" ,build) #:inputs `((,bash) (,build)) #:env-vars `(("NAME" . "second") ("x" . ,(random-text)))))) (set-build-options store #:print-build-trace #t #:multiplexed-build-output? #t #:max-build-jobs 10) (let ((port (open-output-string))) ;; Send the build log to PORT. (parameterize ((current-build-output-port port)) (build-derivations store (list drv1 drv2))) ;; Retrieve the build log; make sure it contains valid "@ build-log" ;; traces that allow us to retrieve each builder's output (we assume ;; there's exactly one "build-output" trace for each builder, which is ;; reasonable.) (let* ((log (get-output-string port)) (started (fold-matches (make-regexp "@ build-started ([^ ]+) - ([^ ]+) ([^ ]+) ([0-9]+)") log '() cons)) (done (fold-matches (make-regexp "@ build-succeeded (.*) - (.*) (.*) (.*)") log '() cons)) (output (fold-matches (make-regexp "@ build-log ([[:digit:]]+) ([[:digit:]]+)\n([A-Za-z .*]+)\n") log '() cons)) (drv-pid (lambda (name) (lambda (m) (let ((drv (match:substring m 1)) (pid (string->number (match:substring m 4)))) (and (string-suffix? name drv) pid))))) (pid-log (lambda (pid) (lambda (m) (let ((n (string->number (match:substring m 1))) (len (string->number (match:substring m 2))) (str (match:substring m 3))) (and (= pid n) (= (string-length str) (- len 1)) str))))) (pid1 (any (drv-pid "one.drv") started)) (pid2 (any (drv-pid "two.drv") started))) (list (any (pid-log pid1) output) (any (pid-log pid2) output))))))) (test-end "store")