code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2015, 2016, 2017, 2018, 2019, 2021 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/>.

#
# Test 'guix environment'.
#

set -e

guix environment --version

tmpdir="t-guix-environment-$$"
gcroot="t-guix-environment-gc-root-$$"
trap 'rm -r "$tmpdir"; rm -f "$gcroot"' EXIT

mkdir "$tmpdir"

# 'guix environment' launches /bin/sh if 'SHELL' is unset, so export 'SHELL'
# since we know it's valid (build environments lack /bin/sh.)
export SHELL

# Check the environment variables for the bootstrap Guile.
guix environment --bootstrap --ad-hoc guile-bootstrap --pure \
     --search-paths > "$tmpdir/a"
guix environment --bootstrap --ad-hoc guile-bootstrap:out --pure \
     --search-paths > "$tmpdir/b"

# $PATH must appear in the search paths, and nothing else.
grep -E '^export PATH=.*profile/bin' "$tmpdir/a"
test "`wc -l < "$tmpdir/a"`" = 1

# Guile must be on $PATH.
test -x `sed -r 's/^export PATH="(.*)"/\1/' "$tmpdir/a"`/guile

cmp "$tmpdir/a" "$tmpdir/b"

# Check '--preserve'.
GUIX_TEST_ABC=1
GUIX_TEST_DEF=2
GUIX_TEST_XYZ=3
export GUIX_TEST_ABC GUIX_TEST_DEF GUIX_TEST_XYZ
guix environment --bootstrap --ad-hoc guile-bootstrap --pure	\
     --preserve='^GUIX_TEST_A' --preserve='^GUIX_TEST_D'	\
     -- "$SHELL" -c set > "$tmpdir/a"
grep '^PATH=' "$tmpdir/a"
grep '^GUIX_TEST_ABC=' "$tmpdir/a"
grep '^GUIX_TEST_DEF=' "$tmpdir/a"
! grep '^GUIX_TEST_XYZ=' "$tmpdir/a"

# Make sure the exit value is preserved.
if guix environment --bootstrap --ad-hoc guile-bootstrap --pure \
        -- guile -c '(exit 42)'
then
    false
else
    test $? = 42
fi

# Make sure 'GUIX_ENVIRONMENT' points to the profile.
guix environment --bootstrap --ad-hoc guile-bootstrap --pure \
     -- "$SHELL" -c 'test -f "$GUIX_ENVIRONMENT/bin/guile"'

# Make sure 'GUIX_ENVIRONMENT' points to the profile when building from a
# manifest.
echo "(use-modules (guix profiles) (gnu packages bootstrap))

(packages->manifest (list %bootstrap-guile))
" > $tmpdir/manifest.scm
guix environment --bootstrap --manifest=$tmpdir/manifest.scm --pure \
     -- "$SHELL" -c 'test -f "$GUIX_ENVIRONMENT/bin/guile"'

# Make sure '--manifest' can be specified multiple times.
cat > "$tmpdir/manifest2.scm" <<EOF
(use-modules (guix) (guix profiles)
             (guix build-system trivial)
             (gnu packages bootstrap))

(packages->manifest
 (list (package
         (inherit %bootstrap-guile)
         (name "eliug")
         (build-system trivial-build-system)
         (arguments
          (quasiquote
           (#:guile ,%bootstrap-guile
            #:builder
            (begin
              (mkdir %output)
              (mkdir (string-append %output "/eliug")))))))))
EOF
guix environment --bootstrap -m "$tmpdir/manifest.scm" \
     -m "$tmpdir/manifest2.scm" --pure \
     -- "$SHELL" -c 'test -f "$GUIX_ENVIRONMENT/bin/guile" && test -d "$GUIX_ENVIRONMENT/eliug"'

# Make sure '-r' works as expected.
rm -f "$gcroot"
expected="`guix environment --bootstrap --ad-hoc guile-bootstrap \
             -- "$SHELL" -c 'echo $GUIX_ENVIRONMENT'`"
guix environment --bootstrap -r "$gcroot" --ad-hoc guile-bootstrap \
     -- guile -c 1
test `readlink "$gcroot"` = "$expected"

# Make sure '-r' is idempotent.
guix environment --bootstrap -r "$gcroot" --ad-hoc guile-bootstrap \
     -- guile -c 1
test `readlink "$gcroot"` = "$expected"
rm "$gcroot"

# Try '-r' with a relative file name.
(cd "$tmpdir"; mkdir "gc-root";
 guix environment --bootstrap -r "gc-root/r" --ad-hoc guile-bootstrap \
      -- guile -c 1;
 rm "gc-root/r"; rmdir "gc-root")

# Same with an absolute file name.
guix environment --bootstrap -r "$PWD/$gcroot" --ad-hoc guile-bootstrap \
     -- guile -c 1
test `readlink "$gcroot"` = "$expected"

case "`uname -m`" in
    x86_64)
	# On x86_64, we should be able to create a 32-bit environment.
	guix environment --bootstrap --ad-hoc guile-bootstrap --pure	\
	     -- guile -c '(exit (string-prefix? "x86_64" %host-type))'
	guix environment --bootstrap --ad-hoc guile-bootstrap --pure	\
	     -s i686-linux						\
	     -- guile -c '(exit (string-prefix? "i686" %host-type))'
	;;
    *)
	echo "nothing to do" >&2
	;;
esac

# Make sure we can build the environment of 'guix'.  There may be collisions
# in its profile (e.g., for 'gzip'), but we have to accept them.
guix environment guix --bootstrap -n

# Try program transformation options.
mkdir "$tmpdir/emacs-36.8"
drv="`guix environment --ad-hoc emacs -n 2>&1 | grep 'emacs.*\.drv'`"
transformed_drv="`guix environment --ad-hoc emacs --with-source="$tmpdir/emacs-36.8" -n 2>&1 | grep 'emacs.*\.drv'`"
test -n "$drv"
test "$drv" != "$transformed_drv"
case "$transformed_drv" in
    *-emacs-36.8.drv) true;;
    *)                false;;
esac
rmdir "$tmpdir/emacs-36.8"

# Transformation options without '--ad-hoc'.
drv="`guix environment -n emacs-geiser 2>&1 | grep '\.drv$'`"
transformed_drv="`guix environment -n emacs-geiser \
  --with-input=emacs-minimal=vim 2>&1 | grep '\.drv$'`"
test "$drv" != "$transformed_drv"
case "$drv" in
    *-emacs-minimal*.drv*) true;;
    *)                     false;;
esac
case "$transformed_drv" in
    *-emacs-minimal*.drv*) false;;
    *)                     true;;
esac
case "$transformed_drv" in
    *-vim*.drv*) true;;
    *)           false;;
esac

if guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null
then
    # Compute the build environment for the initial GNU Make.
    guix environment --bootstrap --no-substitutes --search-paths --pure \
         -e '(@ (guix tests) gnu-make-for-tests)' > "$tmpdir/a"

    # Make sure bootstrap binaries are in the profile.
    profile=`grep "^export PATH" "$tmpdir/a" | sed -r 's|^.*="(.*)/bin"|\1|'`

    # Make sure the bootstrap binaries are all listed where they belong.
    grep -E "^export PATH=\"$profile/bin\""         "$tmpdir/a"
    grep -E "^export CPATH=\"$profile/include\""    "$tmpdir/a"
    grep -E "^export LIBRARY_PATH=\"$profile/lib\"" "$tmpdir/a"
    for dep in bootstrap-binaries-0 gcc-bootstrap-0 glibc-bootstrap-0
    do
	guix gc --references "$profile" | grep "$dep"
    done

    # 'make-boot0' itself must not be listed.
    ! guix gc --references "$profile" | grep make-boot0

    # Make sure that the shell spawned with '--exec' sees the same environment
    # as returned by '--search-paths'.
    guix environment --bootstrap --no-substitutes --pure \
         -e '(@ (guix tests) gnu-make-for-tests)' \
         -- /bin/sh -c 'echo $PATH $CPATH $LIBRARY_PATH' > "$tmpdir/b"
    ( . "$tmpdir/a" ; echo $PATH $CPATH $LIBRARY_PATH ) > "$tmpdir/c"
    cmp "$tmpdir/b" "$tmpdir/c"

    rm "$tmpdir"/*

    # The following test assumes 'make-boot0' has a "debug" output.
    make_boot0_debug="`guix build -e '(@ (guix tests) gnu-make-for-tests)' | grep -e -debug`"
    test "x$make_boot0_debug" != "x"

    # Make sure the "debug" output is not listed.
    ! guix gc --references "$profile" | grep "$make_boot0_debug"

    # Compute the build environment for the initial GNU Make, but add in the
    # bootstrap Guile as an ad-hoc addition.
    guix environment --bootstrap --no-substitutes --search-paths --pure	\
         -e '(@ (guix tests) gnu-make-for-tests)'		\
         --ad-hoc guile-bootstrap > "$tmpdir/a"
    profile=`grep "^export PATH" "$tmpdir/a" | sed -r 's|^.*="(.*)/bin"|\1|'`

    # Make sure the bootstrap binaries are all listed where they belong.
    grep -E "^export PATH=\"$profile/bin\""         "$tmpdir/a"
    grep -E "^export CPATH=\"$profile/include\""    "$tmpdir/a"
    grep -E "^export LIBRARY_PATH=\"$profile/lib\"" "$tmpdir/a"
    for dep in bootstrap-binaries-0 gcc-bootstrap-0 glibc-bootstrap-0 \
				    guile-bootstrap
    do
	guix gc --references "$profile" | grep "$dep"
    done

    # Make sure a package list with plain package objects and package+output
    # tuples can be used with -e.
    expr_list_test_code="
(list (@ (guix tests) gnu-make-for-tests)
      (list (@ (gnu packages bootstrap) %bootstrap-guile) \"out\"))"

    guix environment --bootstrap --ad-hoc --no-substitutes --search-paths \
         --pure -e "$expr_list_test_code" > "$tmpdir/a"
    profile=`grep "^export PATH" "$tmpdir/a" | sed -r 's|^.*="(.*)/bin"|\1|'`

    for dep in make-test-boot0 guile-bootstrap
    do
	guix gc --references "$profile" | grep "$dep"
    done
fi


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2013, 2015, 2017, 2018, 2019 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/>.

#
# Test the `guix gc' command-line utility.
#

guix gc --version

trap "rm -f guix-gc-root" EXIT
rm -f guix-gc-root

# Below we are using 'drv' and 'out' to contain store file names.  If 'drv'
# and 'out' are environment variables, 'list-runtime-roots' will "see" them
# and thus prevent $drv and $out from being garbage-collected.  Using 'unset'
# allows us to make sure these are truly local shell variables and not
# environments variables.
unset drv
unset out

# For some operations, passing extra arguments is an error.
for option in "" "-C 500M" "--verify" "--optimize" "--list-roots"
do
    ! guix gc $option whatever
done

# This should fail.
! guix gc --verify=foo

# Check the references of a .drv.
drv="`guix build guile-bootstrap -d`"
out="`guix build guile-bootstrap`"
test -f "$drv" && test -d "$out"

guix gc --references "$drv" | grep -e -bash
guix gc --references "$out"
guix gc --references "$out/bin/guile"

! guix gc --references /dev/null;

# Check derivers.
guix gc --derivers "$out" | grep "$drv"

# Add then reclaim a .drv file.
drv="`guix build idutils -d`"
test -f "$drv"

guix gc --list-dead | grep "$drv"
guix gc --delete "$drv"
! test -f "$drv"

# Add a .drv, register it as a root.
drv="`guix build --root=guix-gc-root lsh -d`"
test -f "$drv" && test -L guix-gc-root

guix gc --list-roots | grep "$PWD/guix-gc-root"

guix gc --list-live | grep "$drv"
! guix gc --delete "$drv";

rm guix-gc-root
guix gc --list-dead | grep "$drv"
guix gc --delete "$drv"
! test -f "$drv"

# Try a random collection.
guix gc -C 1KiB

# Check trivial error cases.
! guix gc --delete /dev/null;

# Bug #19757
out="`guix build guile-bootstrap`"
test -d "$out"

guix gc --delete "$out"

! test -d "$out"

out="`guix build guile-bootstrap`"
test -d "$out"

guix gc --delete "$out/"

! test -d "$out"

out="`guix build guile-bootstrap`"
test -d "$out"

guix gc --delete "$out/bin/guile"

repo_name: maximed/guix

license: mit


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2020 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/>.

#
# Test the 'guix git authenticate' command-line utility.
#

# Skip if we're not in a Git checkout.
[ -d "$abs_top_srcdir/.git" ] || exit 77

# Skip if there's no 'keyring' branch.
guile -c '(use-modules (git))
  (member "refs/heads/keyring" (branch-list (repository-open ".")))' || \
    exit 77

# Keep in sync with '%default-channels' in (guix channels)!
intro_commit="9edb3f66fd807b096b48283debdcddccfea34bad"
intro_signer="BBB0 2DDF 2CEA F6A8 0D1D  E643 A2A0 6DF2 A33A 54FA"

cache_key="test-$$"

guix git authenticate "$intro_commit" "$intro_signer"	\
     --cache-key="$cache_key" --stats			\
     --end=9549f0283a78fe36f2d4ff2a04ef8ad6b0c02604

rm "$XDG_CACHE_HOME/guix/authentication/$cache_key"

# Commit and signer of the 'v1.0.0' tag.
v1_0_0_commit="6298c3ffd9654d3231a6f25390b056483e8f407c"
v1_0_0_signer="3CE4 6455 8A84 FDC6 9DB4  0CFB 090B 1199 3D9A EBB5" # civodul
v1_0_1_commit="d68de958b60426798ed62797ff7c96c327a672ac"

# This should fail because these commits lack '.guix-authorizations'.
! guix git authenticate "$v1_0_0_commit" "$v1_0_0_signer" \
       --cache-key="$cache_key" --end="$v1_0_1_commit"

# This should work thanks to '--historical-authorizations'.
guix git authenticate "$v1_0_0_commit" "$v1_0_0_signer" 	\
     --cache-key="$cache_key" --end="$v1_0_1_commit" --stats	\
     --historical-authorizations="$abs_top_srcdir/etc/historical-authorizations"


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2015, 2016, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2019 Simon Tournier <zimon.toutoune@gmail.com>
#
# 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/>.

#
# Test the 'guix graph' command-line utility.
#

module_dir="t-guix-graph-$$"
mkdir "$module_dir"
trap "rm -rf $module_dir" EXIT

tmpfile1="$module_dir/t-guix-graph1-$$"
tmpfile2="$module_dir/t-guix-graph2-$$"
trap 'rm -f "$tmpfile1" "$tmpfile2"' EXIT

cat > "$module_dir/foo.scm"<<EOF
(define-module (foo)
  #:use-module (guix packages)
  #:use-module (gnu packages base))

(define-public dummy
  (package (inherit hello)
    (name "dummy")
    (version "42")
    (synopsis "dummy package")
    (description "dummy package. Only used for testing purposes.")))
EOF

guix graph --version

for package in guile-bootstrap coreutils python
do
    for graph in package bag-emerged bag bag-with-origins
    do
	guix graph -t "$graph" "$package" | grep "$package"
    done
done

guix build guile-bootstrap
guix graph -t references guile-bootstrap | grep guile-bootstrap

guix graph -e '(@ (gnu packages bootstrap) %bootstrap-guile)' \
    | grep guile-bootstrap

! guix graph -e +

# Try passing store file names.

guix graph -t references guile-bootstrap > "$tmpfile1"
guix graph -t references `guix build guile-bootstrap` > "$tmpfile2"
cmp "$tmpfile1" "$tmpfile2"

# XXX: Filter the file names in the graph to work around the fact that we get
# a mixture of relative and absolute file names.
guix graph -t derivation coreutils > "$tmpfile1"
guix graph -t derivation `guix build -d coreutils` > "$tmpfile2"
cmp "$tmpfile1" "$tmpfile2"

# Try package transformation options.
guix graph git | grep 'label = "openssl'
guix graph git --with-input=openssl=libressl | grep 'label = "libressl'
! guix graph git --with-input=openssl=libressl | grep 'label = "openssl'

# Try --load-path
guix graph -L $module_dir dummy | grep 'label = "dummy'

# Displaying shortest paths (or lack thereof).
! guix graph --path emacs vim

path="\
emacs
gnutls
guile
libffi"
test "`guix graph --path emacs libffi | cut -d '@' -f1`" = "$path"

# At the derivation level, there's a direct path because libffi is propagated
# via gtk+.
test "`guix graph --path -t derivation emacs libffi | wc -l`" -ge 2


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2013, 2014, 2016, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2016 Jan Nieuwenhuizen <janneke@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/>.

#
# Test the `guix hash' command-line utility.
#

guix hash --version

tmpdir="guix-hash-$$"
trap 'rm -rf "$tmpdir"' EXIT

test `guix hash /dev/null` = 0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73
test `echo -n | guix hash -` = 0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73
test `guix hash -f nix-base32 /dev/null` = 0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73
test `guix hash -f hex /dev/null` = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
test `guix hash -f base32 /dev/null` = 4oymiquy7qobjgx36tejs35zeqt24qpemsnzgtfeswmrw6csxbkq
test `guix hash -H sha512 -f hex /dev/null` = cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
test `guix hash -H sha1 -f base64 /dev/null` = "2jmj7l5rSw0yVb/vlWAYkK/YBwk="

! guix hash -H abcd1234 /dev/null

mkdir "$tmpdir"
echo -n executable > "$tmpdir/exe"
chmod +x "$tmpdir/exe"
( cd "$tmpdir" ; ln -s exe symlink )
mkdir "$tmpdir/subdir"

test `guix hash -r "$tmpdir"` = 10k1lw41wyrjf9mxydi0is5nkpynlsvgslinics4ppir13g7d74p
test `guix hash -r "$tmpdir" -H sha512` = 301ra58c2vahczzxiyfin41mpyb0ljh4dh9zn3ijvwviaw1j40sfzw5skh9x945da88n3785ggifzig7acd6k72h0mpsc20m1f66m9n

# Without '-r', this should fail.
! guix hash "$tmpdir"

# This should fail because /dev/null is a character device, which
# the archive format doesn't support.
! guix hash -r /dev/null

# Adding a .git directory
mkdir "$tmpdir/.git"
touch "$tmpdir/.git/foo"

# ...changes the hash
test `guix hash -r $tmpdir` = 0a50z04zyzf7pidwxv0nwbj82pgzbrhdy9562kncnvkcfvb48m59

# ...but remains the same when using `-x'
test `guix hash -r $tmpdir -x` = 10k1lw41wyrjf9mxydi0is5nkpynlsvgslinics4ppir13g7d74p

# Without '-r', this should fail.
! guix hash "$tmpdir"


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2014 Cyril Roelandt <tipecaml@gmail.com>
#
# 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/>.

#
# Test the `guix lint' command-line utility.
#

guix lint --version

# Choose a module directory not below any %LOAD-PATH component.  This is
# necessary when testing '-L' with a relative file name.
module_dir="$(mktemp -d)"

mkdir -p "$module_dir"
trap "rm -rf $module_dir" EXIT

cat > "$module_dir/foo.scm"<<EOF
(define-module (foo)
  #:use-module (guix packages)
  #:use-module (gnu packages base))

(define-public dummy
  (package (inherit hello)
    (name "dummy")
    (version "42")
    (synopsis "dummy package")
    (description "dummy package. Only used for testing purposes.")))
EOF

GUIX_PACKAGE_PATH="$module_dir"
export GUIX_PACKAGE_PATH

grep_warning ()
{
    res=`echo "$1" | grep -E -c "(synopsis|description) should"`
    echo $res
}

# Three issues with the dummy package:
# 1) the synopsis starts with the package name;
# 2) the synopsis starts with a lower-case letter;
# 3) the description has a single space following the end-of-sentence period.

out=`guix lint -c synopsis,description dummy 2>&1`
test `grep_warning "$out"` -eq 3

out=`guix lint -c synopsis dummy 2>&1`
test `grep_warning "$out"` -eq 2

out=`guix lint -c description dummy 2>&1`
test `grep_warning "$out"` -eq 1

out=`guix lint -c description,synopsis dummy 2>&1`
test `grep_warning "$out"` -eq 3

guix lint -c synopsis,invalid-checker dummy 2>&1 | \
   grep -q 'invalid-checker: invalid checker'

# Make sure specifying multiple packages works.
guix lint -c inputs-should-be-native dummy dummy@42 dummy

# Use --load-path instead.
unset GUIX_PACKAGE_PATH

out=`guix lint -L $module_dir -c synopsis,description dummy 2>&1`
test `grep_warning "$out"` -eq 3

# Make sure specifying multiple packages works.
guix lint -L $module_dir -c inputs-should-be-native dummy dummy@42 dummy

# Test '-L' with a relative file name.  'guix lint' will see "t-xyz/foo.scm"
# (instead of "foo.scm") and will thus fail to find it in %LOAD-PATH.  Check
# that it does find it anyway.  See <https://bugs.gnu.org/42543>.
(cd "$module_dir"/.. ; guix lint -c formatting -L "$(basename "$module_dir")" dummy@42) 2>&1 > "$module_dir/out"
test -z "$(cat "$module_dir/out")"

# Likewise, when there's a warning, 'package-field-location' used to crash
# because it can't find "t-xyz/foo.scm".  See <https://bugs.gnu.org/46390>.
(cd "$module_dir"/.. ; guix lint -c synopsis -L "$(basename "$module_dir")" dummy@42) 2>&1 > "$module_dir/out"
grep_warning "`cat "$module_dir/out"`"


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2018, 2019 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/>.

#
# Test the 'guix pack --localstatedir' command-line utility.
#

guix pack --version

# 'guix pack --localstatedir' produces derivations that depend on
# guile-sqlite3 and guile-gcrypt.  To make that relatively inexpensive, run
# the test in the user's global store if possible, on the grounds that
# binaries may already be there or can be built or downloaded inexpensively.

storedir="`guile -c '(use-modules (guix config))(display %storedir)'`"
localstatedir="`guile -c '(use-modules (guix config))(display %localstatedir)'`"
NIX_STORE_DIR="$storedir"
GUIX_DAEMON_SOCKET="$localstatedir/guix/daemon-socket/socket"
export NIX_STORE_DIR GUIX_DAEMON_SOCKET

if ! guile -c '(use-modules (guix)) (exit (false-if-exception (open-connection)))'
then
    exit 77
fi

# Build a tarball with '--localstatedir'
the_pack="`guix pack -C none --localstatedir --profile-name=current-guix \
            guile-bootstrap`"
test_directory="`mktemp -d`"
trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT

cd "$test_directory"
tar -xf "$the_pack"

profile="`find -name current-guix`"
test "`readlink $profile`" = "current-guix-1-link"
test -s "`dirname $profile`/../../../db/db.sqlite"
test -x ".`guix build guile-bootstrap`/bin/guile"
cd -

# Make sure the store database is not completely bogus.
guile -c "(use-modules (sqlite3) (guix config) (ice-9 match))

  (define db
    (sqlite-open (string-append \"$test_directory\"
                                %localstatedir
                               \"/guix/db/db.sqlite\")
                 SQLITE_OPEN_READONLY))

  (define stmt
    (sqlite-prepare db \"SELECT * FROM ValidPaths;\"))

  (match (sqlite-fold cons '() stmt)
    ((#(ids paths hashes times derivers sizes) ...)
     (exit (member \"`guix build guile-bootstrap`\" paths))))"


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2020 Eric Bavier <bavier@posteo.net>
#
# 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/>.

#
# Test the 'guix pack --relocatable' using the external store, if any.
#

guix pack --version

# 'guix pack --relocatable' requires a C compiler and libc.a, which our
# bootstrap binaries don't provide.  To make the test relatively inexpensive,
# run it on the user's global store if possible, on the grounds that binaries
# may already be there or can be built or downloaded inexpensively.

storedir="`guile -c '(use-modules (guix config))(display %storedir)'`"
localstatedir="`guile -c '(use-modules (guix config))(display %localstatedir)'`"
NIX_STORE_DIR="$storedir"
GUIX_DAEMON_SOCKET="$localstatedir/guix/daemon-socket/socket"
export NIX_STORE_DIR GUIX_DAEMON_SOCKET

if ! guile -c '(use-modules (guix)) (exit (false-if-exception (open-connection)))'
then
    exit 77
fi

# Attempt to run the given command in a namespace where the store is
# invisible.  This makes sure the presence of the store does not hide
# problems.
run_without_store ()
{
    if unshare -r true		# Are user namespaces supported?
    then
	# Run that relocatable executable in a user namespace where we "erase"
	# the store by mounting an empty file system on top of it.  That way,
	# we exercise the wrapper code that creates the user namespace and
	# bind-mounts the store.
	unshare -mrf sh -c 'mount -t tmpfs -o ro none "$NIX_STORE_DIR"; '"$*"
    else
	# Run the relocatable program in the current namespaces.  This is a
	# weak test because we're going to access store items from the host
	# store.
	sh -c "$*"
    fi
}

# Wait for the given file to show up.  Error out if it doesn't show up in a
# timely fashion.
wait_for_file ()
{
    i=0
    while ! test -f "$1" && test $i -lt 20
    do
	sleep 0.3
	i=`expr $i + 1`
    done
    test -f "$1"
}

test_directory="`mktemp -d`"
export test_directory
trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT

if unshare -r true
then
    # Test the 'userns' execution engine.
    tarball="`guix pack -R -S /Bin=bin sed`"
    (cd "$test_directory"; tar xvf "$tarball")

    run_without_store "$test_directory/Bin/sed" --version > "$test_directory/output"
    grep 'GNU sed' "$test_directory/output"

    # Same with an explicit engine.
    run_without_store GUIX_EXECUTION_ENGINE="userns" \
		      "$test_directory/Bin/sed" --version > "$test_directory/output"
    grep 'GNU sed' "$test_directory/output"

    # Check whether the exit code is preserved.
    ! run_without_store "$test_directory/Bin/sed" --does-not-exist

    chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
else
    echo "'userns' execution tests skipped" >&2
fi

case "`uname -m`" in
    x86_64|i?86)
	# Try '-RR' and PRoot.
	tarball="`guix pack -RR -S /Bin=bin sed`"
	tar tvf "$tarball" | grep /bin/proot
	(cd "$test_directory"; tar xf "$tarball")
	run_without_store GUIX_EXECUTION_ENGINE="proot" \
	"$test_directory/Bin/sed" --version > "$test_directory/output"
	grep 'GNU sed' "$test_directory/output"

	# Now with fakechroot.
	run_without_store GUIX_EXECUTION_ENGINE="fakechroot" \
	"$test_directory/Bin/sed" --version > "$test_directory/output"
	grep 'GNU sed' "$test_directory/output"
	unset GUIX_EXECUTION_ENGINE

	chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*

	if unshare -r true
	then
	    # Check whether the store contains everything it should.  Check
	    # once when erasing $STORE_PARENT ("/gnu") and once when erasing
	    # $NIX_STORE_DIR ("/gnu/store").
	    tarball="`guix pack -RR -S /bin=bin bash-minimal`"
	    (cd "$test_directory"; tar xf "$tarball")

	    STORE_PARENT="`dirname $NIX_STORE_DIR`"
	    export STORE_PARENT

	    for engine in userns proot fakechroot
	    do
		for i in $(guix gc -R $(guix build bash-minimal | grep -v -e '-doc$'))
		do
		    unshare -mrf sh -c "mount -t tmpfs none \"$NIX_STORE_DIR\"; GUIX_EXECUTION_ENGINE=$engine $test_directory/bin/sh -c 'echo $NIX_STORE_DIR/*'" | grep $(basename $i)
		    unshare -mrf sh -c "mount -t tmpfs none \"$STORE_PARENT\";  GUIX_EXECUTION_ENGINE=$engine $test_directory/bin/sh -c 'echo $NIX_STORE_DIR/*'" | grep $(basename $i)
		done
	    done

	    chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
	fi
	;;
    *)
	echo "skipping PRoot and Fakechroot tests" >&2
	;;
esac

if unshare -r true
then
    # Check what happens if the wrapped binary forks and leaves child
    # processes behind, like a daemon.  The root file system should remain
    # available to those child processes.  See <https://bugs.gnu.org/44261>.
    cat > "$test_directory/manifest.scm" <<EOF
(use-modules (guix))

(define daemon
  (program-file "daemon"
                #~(begin
                    (use-modules (ice-9 match)
                                 (ice-9 ftw))

                    (call-with-output-file "parent-store"
                      (lambda (port)
                        (write (scandir (ungexp (%store-prefix)))
                               port)))

                    (match (primitive-fork)
                      (0 (sigaction SIGHUP (const #t))
                         (call-with-output-file "pid"
                           (lambda (port)
                             (display (getpid) port)))
                         (pause)
                         (call-with-output-file "child-store"
                           (lambda (port)
                             (write (scandir (ungexp (%store-prefix)))
                                    port))))
                      (_ #t)))))

(define package
  (computed-file "package"
                 #~(let ((out (ungexp output)))
                     (mkdir out)
                     (mkdir (string-append out "/bin"))
                     (symlink (ungexp daemon)
                              (string-append out "/bin/daemon")))))

(manifest (list (manifest-entry
                  (name "daemon")
                  (version "0")
                  (item package))))
EOF

    tarball="$(guix pack -S /bin=bin -R -m "$test_directory/manifest.scm")"
    (cd "$test_directory"; tar xf "$tarball")

    # Run '/bin/daemon', which forks, then wait for the child, send it SIGHUP
    # so that it dumps its view of the store, and make sure the child and
    # parent both see the same store contents.
    (cd "$test_directory"; run_without_store ./bin/daemon)
    wait_for_file "$test_directory/pid"
    kill -HUP $(cat "$test_directory/pid")
    wait_for_file "$test_directory/child-store"
    diff -u "$test_directory/parent-store" "$test_directory/child-store"

    chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*
fi

# Ensure '-R' works with outputs other than "out".
tarball="`guix pack -R -S /share=share groff:doc`"
(cd "$test_directory"; tar xf "$tarball")
test -d "$test_directory/share/doc/groff/html"
chmod -Rf +w "$test_directory"; rm -rf "$test_directory"/*

# Ensure '-R' applies to propagated inputs.  Failing to do that, it would fail
# with a profile collision error in this case because 'python-scipy'
# propagates 'python-numpy'.  See <https://bugs.gnu.org/42510>.
guix pack -RR python-numpy python-scipy --no-grafts -n

# Check that packages that mix executable and support files (e.g. git) in the
# "binary" directories still work after wrapped.
cat >"$test_directory/manifest.scm" <<'EOF'
(use-modules (guix) (guix profiles) (guix search-paths)
             (gnu packages bootstrap))
(manifest
 (list (manifest-entry
        (name "test") (version "0")
        (item (file-union "test"
                          `(("bin/hello"
                             ,(program-file
                               "hello"
                               #~(begin
                                   (add-to-load-path (getenv "HELLO_EXEC_PATH"))
                                   (display (load-from-path "msg"))(newline))
                               #:guile %bootstrap-guile))
                            ("libexec/hello/msg"
                             ,(plain-file "msg" "42")))))
        (search-paths
         (list (search-path-specification
                (variable "HELLO_EXEC_PATH")
                (files '("libexec/hello"))
                (separator #f)))))))
EOF
tarball="`guix pack -RR -S /opt= -m $test_directory/manifest.scm`"
(cd "$test_directory"; tar xvf "$tarball")
( export GUIX_PROFILE=$test_directory/opt
  . $GUIX_PROFILE/etc/profile
  run_without_store "$test_directory/opt/bin/hello" > "$test_directory/output" )
cat "$test_directory/output"
test "`cat $test_directory/output`" = "42"


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
# Copyright © 2018, 2019, 2020 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/>.

#
# Test the `guix pack' command-line utility.
#

# A network connection is required to build %bootstrap-coreutils&co,
# which is required to run these tests with the --bootstrap option.
if ! guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null; then
    exit 77
fi

guix pack --version

# Use --no-substitutes because we need to verify we can do this ourselves.
GUIX_BUILD_OPTIONS="--no-substitutes"
export GUIX_BUILD_OPTIONS

test_directory="`mktemp -d`"
trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT

# Compute the derivation of a pack.
drv="`guix pack coreutils -d --no-grafts`"
guix gc -R "$drv" | grep "`guix build coreutils -d --no-grafts`"

# Compute the derivation of a cross-compiled pack.  Make sure it refers to the
# cross-compiled package and not to the native package.
drv="`guix pack idutils -d --no-grafts --target=arm-linux-gnueabihf`"
guix gc -R "$drv" | \
    grep "`guix build idutils --target=arm-linux-gnueabihf -d --no-grafts`"
! guix gc -R "$drv" | grep "`guix build idutils -d --no-grafts`"

# Build a tarball with no compression.
guix pack --compression=none --bootstrap guile-bootstrap

# Build a tarball (with compression).  Check that '-e' works as well.
out1="`guix pack --bootstrap guile-bootstrap`"
out2="`guix pack --bootstrap -e '(@ (gnu packages bootstrap) %bootstrap-guile)'`"
test -n "$out1"
test "$out1" = "$out2"

# Test '--root'.
guix pack -r "$test_directory/my-guile" --bootstrap guile-bootstrap
test "`readlink "$test_directory/my-guile"`" = "$out1"
guix gc --list-roots | grep "^$test_directory/my-guile$"
rm "$test_directory/my-guile"

# Build a tarball with a symlink.
the_pack="`guix pack --bootstrap -S /opt/gnu/bin=bin guile-bootstrap`"

# Try to extract it.  Note: we cannot test whether /opt/gnu/bin/guile itself
# exists because /opt/gnu/bin may be an absolute symlink to a store item that
# has been GC'd.
cd "$test_directory"
tar -xf "$the_pack"
test -L opt/gnu/bin

is_available () {
    # Use the "type" shell builtin to see if the program is on PATH.
    type "$1" > /dev/null
}

if is_available chroot && is_available unshare && unshare -r true; then
    # Verify we can use what we built.
    unshare -r chroot . /opt/gnu/bin/guile --version
    cd -
else
    echo "warning: skipped some verification because chroot or unshare is unavailable" >&2
fi

# For the tests that build Docker images below, we currently have to use
# --dry-run because if we don't, there are only two possible cases:
#
#     Case 1: We do not use --bootstrap, and the build takes hours to finish
#             because it needs to build tar etc.
#
#     Case 2: We use --bootstrap, and the build fails because the bootstrap
#             Guile cannot dlopen shared libraries.  Not to mention the fact
#             that we would still have to build many non-bootstrap inputs
#             (e.g., guile-json) in order to create the Docker image.

# Build a Docker image.
guix pack --dry-run --bootstrap -f docker guile-bootstrap

# Build a Docker image with a symlink.
guix pack --dry-run --bootstrap -f docker -S /opt/gnu=/ guile-bootstrap

# Build a tarball pack of cross-compiled software.  Use coreutils because
# guile-bootstrap is not intended to be cross-compiled.
guix pack --dry-run --bootstrap --target=arm-unknown-linux-gnueabihf coreutils

# Likewise, 'guix pack -R' requires a full-blown toolchain (because
# 'glibc-bootstrap' lacks 'libc.a'), hence '--dry-run'.
guix pack -R --dry-run --bootstrap -S /mybin=bin guile-bootstrap

# Make sure package transformation options are honored.
mkdir -p "$test_directory"
drv1="`guix pack --no-grafts -n guile 2>&1 | grep pack.*\.drv`"
drv2="`guix pack --no-grafts -n --with-source=guile=$test_directory guile 2>&1 | grep pack.*\.drv`"
test -n "$drv1"
test "$drv1" != "$drv2"

# Try '--manifest' options.
cat > "$test_directory/manifest1.scm" <<EOF
(specifications->manifest '("guile"))
EOF
cat > "$test_directory/manifest2.scm" <<EOF
(specifications->manifest '("emacs"))
EOF
drv="`guix pack --no-grafts -d -m "$test_directory/manifest1.scm" -m "$test_directory/manifest2.scm"`"
guix gc -R "$drv" | grep `guix build guile -d --no-grafts`
guix gc -R "$drv" | grep `guix build emacs -d --no-grafts`


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2019, 2020 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/>.

#
# Test the `guix package' aliases.
#

guix install --version

readlink_base ()
{
    basename `readlink "$1"`
}

profile="t-profile-$$"
rm -f "$profile"

trap 'rm -f "$profile" "$profile-"[0-9]*' EXIT

guix install --bootstrap guile-bootstrap -p "$profile"
test -x "$profile/bin/guile"

# Make sure '-r' isn't passed as-is to 'guix package'.
! guix install -r guile-bootstrap -p "$profile" --bootstrap
test -x "$profile/bin/guile"

# Use a package transformation option and make sure it's recorded.
guix install --bootstrap guile-bootstrap -p "$profile" \
     --with-input=libreoffice=inkscape
test -x "$profile/bin/guile"
grep "libreoffice=inkscape" "$profile/manifest"

guix upgrade --version
guix upgrade -n
guix upgrade gui.e -n
! guix upgrade foo bar -n;

guix remove --version
guix remove --bootstrap guile-bootstrap -p "$profile"
! test -x "$profile/bin/guile"
test `guix package -p "$profile" -I | wc -l` -eq 0

! guix remove -p "$profile" this-is-not-installed --bootstrap

! guix remove -i guile-bootstrap -p "$profile" --bootstrap

guix search '\<board\>' game | grep '^name: gnubg'

guix show --version
guix show guile
guix show python@3 | grep "^name: python"

# "python@2" exists but is deprecated; make sure it doesn't show up.
! guix show python@2

# Specifying multiple packages.
output="`guix show sed grep | grep ^name:`"
test "$output" = "name: sed
name: grep"


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2012, 2013, 2014, 2015, 2017, 2019 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
# Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
#
# 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/>.

#
# Test the `guix package' command-line utility.  This test requires network
# access and is skipped when that is lacking.
#

guix package --version

readlink_base ()
{
    basename `readlink "$1"`
}

# Return true if a typical shebang in the store would exceed Linux's default
# static limit.
shebang_too_long ()
{
    test `echo $NIX_STORE_DIR/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bootstrap-binaries-0/bin/bash | wc -c` \
	 -ge 128
}

if ! guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null \
	|| shebang_too_long
then
    # Skipping.
    exit 77
fi

profile="t-profile-$$"
profile_alt="t-profile-alt-$$"
rm -f "$profile"

trap 'rm -f "$profile" "$profile_alt" "$profile-"[0-9]* "$profile_alt-"[0-9]* ; rm -rf t-home-'"$$" EXIT

guix package --bootstrap -p "$profile" -i guile-bootstrap
test -L "$profile" && test -L "$profile-1-link"
! test -f "$profile-2-link"
test -f "$profile/bin/guile"

boot_make="(@ (guix tests) gnu-make-for-tests)"
boot_make_drv="`guix build -e "$boot_make" | grep -v -e -debug`"
guix package --bootstrap -p "$profile" -i "$boot_make_drv"
test -L "$profile-2-link"
test -f "$profile/bin/make" && test -f "$profile/bin/guile"

# Check whether `--list-installed' works.
# XXX: Change the tests when `--install' properly extracts the package
# name and version string.
installed="`guix package -p "$profile" --list-installed | cut -f1 | xargs echo | sort`"
case "x$installed" in
    "guile-bootstrap make-boot0")
        true;;
    "make-boot0 guile-bootstrap")
        true;;
    "*")
        false;;
esac

test "`guix package -p "$profile" -I 'g.*e' | cut -f1`" = "guile-bootstrap"

guix package --bootstrap -p "$profile_alt" -i gcc-bootstrap
installed="`guix package -p "$profile" -p "$profile_alt" -I | cut -f1 | xargs echo | sort`"
case "x$installed" in
    "gcc-bootstrap guile-bootstrap make-boot0")
        true;;
    "*")
        false;;
esac
test "`guix package -p "$profile_alt" -p "$profile" -I | wc -l`" = "3"
rm "$profile_alt"

# List generations.
test "`guix package -p "$profile" -l | cut -f1 | grep guile | head -n1`" \
     = "  guile-bootstrap"

# Exit with 1 when a generation does not exist.
! guix package -p "$profile" --list-generations=42
! guix package -p "$profile" --switch-generation=99

# Remove a package.
guix package --bootstrap -p "$profile" -r "guile-bootstrap"
test -L "$profile-3-link"
test -f "$profile/bin/make" && ! test -f "$profile/bin/guile"

# Roll back.
guix package --roll-back -p "$profile"
test "`readlink_base "$profile"`" = "$profile-2-link"
test -x "$profile/bin/guile" && test -x "$profile/bin/make"
guix package --roll-back -p "$profile"
test "`readlink_base "$profile"`" = "$profile-1-link"
test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"

# Switch to the rolled generation and switch back.
guix package -p "$profile" --switch-generation=2
test "`readlink_base "$profile"`" = "$profile-2-link"
guix package -p "$profile" --switch-generation=-1
test "`readlink_base "$profile"`" = "$profile-1-link"

# Move to the empty profile.
for i in `seq 1 3`
do
    guix package --bootstrap --roll-back -p "$profile"
    ! test -f "$profile/bin"
    ! test -f "$profile/lib"
    test "`readlink_base "$profile"`" = "$profile-0-link"
done

# Test that '--list-generations' does not output the zeroth generation.
test -z "`guix package -p "$profile" -l 0`"

# Reinstall after roll-back to the empty profile.
guix package --bootstrap -p "$profile" -e "$boot_make"
test "`readlink_base "$profile"`" = "$profile-1-link"
test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"

# Check that the first generation is the current one.
test "`guix package -p "$profile" -l 1 | cut -f3 | head -n1`" = "(current)"

# Roll-back to generation 0, and install---all at once.
guix package --bootstrap -p "$profile" --roll-back -i guile-bootstrap
test "`readlink_base "$profile"`" = "$profile-1-link"
test -x "$profile/bin/guile" && ! test -x "$profile/bin/make"

# Install Make.
guix package --bootstrap -p "$profile" -e "$boot_make"
test "`readlink_base "$profile"`" = "$profile-2-link"
test -x "$profile/bin/guile" && test -x "$profile/bin/make"
grep "`guix build -e "$boot_make"`" "$profile/manifest"

# Make a "hole" in the list of generations, and make sure we can
# roll back and switch "over" it.
rm "$profile-1-link"
guix package --bootstrap -p "$profile" --roll-back
test "`readlink_base "$profile"`" = "$profile-0-link"
guix package -p "$profile" --switch-generation=+1
test "`readlink_base "$profile"`" = "$profile-2-link"

# Make sure LIBRARY_PATH gets listed by `--search-paths'.
guix package --bootstrap -p "$profile" -i guile-bootstrap -i gcc-bootstrap
guix package -p "$profile" --search-paths | grep LIBRARY_PATH

# Roll back so we can delete #3 below.
guix package -p "$profile" --switch-generation=2

# Delete the third generation and check that it was actually deleted.
guix package -p "$profile" --delete-generations=3
test -z "`guix package -p "$profile" -l 3`"

# Search path of combined profiles.  'LIBRARY_PATH' should show up only in the
# combination, not in the individual profiles.
rm "$profile"
guix package --bootstrap -p "$profile" -i guile-bootstrap
guix package --bootstrap -p "$profile_alt" -i gcc-bootstrap
! guix package -p "$profile" --search-paths | grep LIBRARY_PATH
guix package -p "$profile" -p "$profile_alt" --search-paths \
     | grep "LIBRARY_PATH.*$profile/lib.$profile_alt/lib"

# Simulate an upgrade and make sure the package order is preserved.
module_dir="t-guix-package-net-$$"
trap 'rm -rf "$module_dir"' EXIT

mkdir "$module_dir"
cat > "$module_dir/new.scm" <<EOF
(define-module (new)
  #:use-module (guix)
  #:use-module (gnu packages bootstrap))

(define-public new-guile
  (package (inherit %bootstrap-guile)
           (version (string-append "42." (getenv "V_MINOR")))))
(define-public new-gcc
  (package (inherit %bootstrap-gcc)
           (version (string-append "77." (getenv "V_MINOR")))))
EOF

guix package --bootstrap -p "$profile" -i gcc-bootstrap
installed="`guix package -p "$profile" -I | cut -f1`"

for i in 1 2
do
    V_MINOR="$i"
    export V_MINOR

    guix package -p "$profile" --bootstrap -L "$module_dir" -u .
    post_upgrade="`guix package -p "$profile" -I | cut -f1`"
    test "$post_upgrade" = "$installed"
done

#
# Try with the default profile.
#

XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
export XDG_CACHE_HOME
HOME="$PWD/t-home-$$"
export HOME

mkdir -p "$HOME"

# Get the canonical directory name so that 'guix package' recognizes it.
HOME="`cd $HOME; pwd -P`"

guix package --bootstrap -e "$boot_make"
test -f "$HOME/.guix-profile/bin/make"

guix package --bootstrap --roll-back
! test -f "$HOME/.guix-profile/bin/make"


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.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/>.

#
# Test the `guix package' command-line utility.
#

guix package --version

readlink_base ()
{
    basename `readlink "$1"`
}

module_dir="t-guix-package-$$"
profile="t-profile-$$"
tmpfile="t-guix-package-file-$$"
rm -f "$profile" "$tmpfile"

trap 'rm -f "$profile" "$profile.lock" "$profile-"[0-9]* "$tmpfile"; rm -rf "$module_dir" t-home-'"$$" EXIT

# Use `-e' with a non-package expression.
! guix package --bootstrap -e +

# Install a store item and make sure the version and output in the manifest
# are correct.
guix package --bootstrap -p "$profile" -i `guix build guile-bootstrap`
test "`guix package -A guile-bootstrap | cut -f 1-2`" \
     = "`guix package -p "$profile" -I | cut -f 1-2`"
test "`guix package -p "$profile" -I | cut -f 3`" = "out"
rm "$profile"

guix package --bootstrap -p "$profile" -i guile-bootstrap
test -L "$profile" && test -L "$profile-1-link"
test -f "$profile/bin/guile"

# Make sure the profile is a GC root.
guix gc --list-live | grep "`readlink "$profile-1-link"`"

# Installing the same package a second time does nothing.
guix package --bootstrap -p "$profile" -i guile-bootstrap
test -L "$profile" && test -L "$profile-1-link"
! test -f "$profile-2-link"
test -f "$profile/bin/guile"

# Collisions are properly flagged (in this case, 'g-wrap' propagates
# guile@2.2, which conflicts with guile@2.0.)
! guix package --bootstrap -n -p "$profile" -i g-wrap guile@2.0

guix package --bootstrap -n -p "$profile" -i g-wrap guile@2.0 \
     --allow-collisions

# No search path env. var. here.
guix package -p "$profile" --search-paths
guix package -p "$profile" --search-paths | grep '^export PATH='
test "`guix package -p "$profile" --search-paths | wc -l`" = 1  # $PATH
( set -e; set -x;						\
  eval `guix package --search-paths=prefix -p "$PWD/$profile"`;	\
  test "`type -P guile`" = "$PWD/$profile/bin/guile" ;		\
  type -P rm )

# Exit with 1 when a generation does not exist.
! guix package -p "$profile" --delete-generations=42

# Exit with 0 when trying to delete the zeroth generation.
guix package -p "$profile" --delete-generations=0

# Make sure multiple arguments to -i works.
guix package --bootstrap -i guile zile -p "$profile" -n

# Make sure the `:' syntax works.
guix package --bootstrap -i "glibc:debug" -p "$profile" -n

# Make sure nonexistent outputs are reported.
guix package --bootstrap -i "guile-bootstrap:out" -p "$profile" -n
! guix package --bootstrap -i "guile-bootstrap:does-not-exist" -p "$profile" -n
! guix package --bootstrap -i "guile-bootstrap:does-not-exist" -p "$profile"

# Make sure we get an error when trying to remove something that's not
# installed.
! guix package --bootstrap -r something-not-installed -p "$profile"

# Check whether `--list-available' returns something sensible.
guix package -p "$profile" -A 'gui.*e' | grep guile

# Check whether `--show' returns something sensible.
guix package --show=guile | grep "^name: guile"

# Ensure `--show' doesn't fail for packages with non-package inputs.
guix package --show=texlive

# Fail for non-existent packages or package/version pairs.
! guix package --show=does-not-exist
! guix package --show=emacs@42

# Search.
LC_MESSAGES=C
export LC_MESSAGES
test "`guix package -s "An example GNU package" | grep ^name:`" = \
    "name: hello"
test -z "`guix package -s "n0t4r341p4ck4g3"`"

# Search with one and then two regexps.
# First we get printed circuit boards *and* board games.
guix package -s '\<board\>' > "$tmpfile"
grep '^name: pcb' "$tmpfile"
grep '^name: gnubg' "$tmpfile"

# Second we get only board games.
guix package -s '\<board\>' -s game > "$tmpfile"
grep -v '^name: pcb' "$tmpfile" > /dev/null
grep '^name: gnubg' "$tmpfile"

rm -f "$tmpfile"

# Make sure deprecated packages don't show up: <https://bugs.gnu.org/30566>.
mkdir "$module_dir"
cat > "$module_dir/foo.scm"<<EOF
(define-module (foo)
  #:use-module (guix packages)
  #:use-module (gnu packages base))

(define-public deprecated
  (deprecated-package "fileutils" coreutils))
EOF

guix build -L "$module_dir" -e '(@ (foo) deprecated)' -n
test "`guix package -L "$module_dir" -s ^fileutils$ | grep ^name:`" = ""

rm -rf "$module_dir"

# Make sure `--search' can display all the packages.
guix package --search="" > /dev/null

# There's no generation older than 12 months, so the following command should
# have no effect.
generation="`readlink_base "$profile"`"
! guix package -p "$profile" --delete-generations=12m
test "`readlink_base "$profile"`" = "$generation"

# The following command should not delete the current generation, even though
# it matches the given pattern (see <http://bugs.gnu.org/19978>.)  And since
# there's nothing else to delete, it should just fail.
guix package --list-generations -p "$profile"
! guix package --bootstrap -p "$profile" --delete-generations=1..
test "`readlink_base "$profile"`" = "$generation"

# Make sure $profile is a GC root at this point.
real_profile="`readlink -f "$profile"`"
! guix gc -d "$real_profile"
test -d "$real_profile"

# Now, let's remove all the symlinks to $real_profile, and make sure
# $real_profile is no longer a GC root.
rm "$profile" "$profile"-[0-9]-link
guix gc -d "$real_profile"
[ ! -d "$real_profile" ]

# Package transformations.

# Make sure we get the right version number when using '--with-source'.
mkdir "$module_dir"
emacs_tarball="$module_dir/emacs-42.5.9rc7.tar.gz"
touch "$emacs_tarball"
guix package -p "$profile" -i emacs --with-source="$emacs_tarball" -n \
     2> "$tmpfile"
grep -E 'emacs[[:blank:]]+42\.5\.9rc7' "$tmpfile"
rm "$emacs_tarball" "$tmpfile"
rmdir "$module_dir"

# Install with package transformations.
guix install --bootstrap -p "$profile" sed --with-input=sed=guile-bootstrap
grep "sed=guile-bootstrap" "$profile/manifest"
test "$(readlink -f "$profile/bin/guile")" \
     = "$(guix build guile-bootstrap)/bin/guile"
test ! -f "$profile/bin/sed"

# Make sure the package transformation is preserved.
guix package --bootstrap -p "$profile" -u
grep "sed=guile-bootstrap" "$profile/manifest"
test "$(readlink -f "$profile/bin/guile")" \
     = "$(guix build guile-bootstrap)/bin/guile"
test ! -f "$profile/bin/sed"
rm "$profile" "$profile"-[0-9]-link

# Profiles with a relative file name.  Make sure we don't create dangling
# symlinks--see bug report at
# <https://lists.gnu.org/archive/html/guix-devel/2018-07/msg00036.html>.
mkdir -p "$module_dir/foo"
( cd "$module_dir" ;						\
  guix package --bootstrap -i guile-bootstrap -p foo/prof )
test -f "$module_dir/foo/prof/bin/guile"
rm "$module_dir/foo"/*
rmdir "$module_dir/foo"
rmdir "$module_dir"

#
# Try with the default profile.
#

XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
export XDG_CACHE_HOME
HOME="$PWD/t-home-$$"
export HOME

mkdir -p "$HOME"

# Get the canonical directory name so that 'guix package' recognizes it.
HOME="`cd $HOME; pwd -P`"

guix package --bootstrap -i guile-bootstrap
test -L "$HOME/.guix-profile"
test -f "$HOME/.guix-profile/bin/guile"

# Move to the empty profile.
default_profile="`readlink "$HOME/.guix-profile"`"
for i in `seq 1 3`
do
    # Make sure the current generation is a GC root.
    profile_link="`readlink "$default_profile"`"
    guix gc --list-live | grep "`readlink "$profile_link"`"

    guix package --bootstrap --roll-back
    ! test -f "$HOME/.guix-profile/bin"
    ! test -f "$HOME/.guix-profile/lib"
    test "`readlink "$default_profile"`" = "`basename $default_profile-0-link`"
done

# Check whether '-p ~/.guix-profile' makes any difference.
# See <http://bugs.gnu.org/17939>.
! test -e "$HOME/.guix-profile-0-link"
! test -e "$HOME/.guix-profile-1-link"
guix package --bootstrap -p "$HOME/.guix-profile" -i guile-bootstrap
! test -e "$HOME/.guix-profile-1-link"
guix package --bootstrap --roll-back -p "$HOME/.guix-profile"
! test -e "$HOME/.guix-profile-0-link"

# Extraneous argument.
! guix package install foo-bar

# Make sure the "broken pipe" doesn't yield an error.
# Note: 'pipefail' is a Bash-specific option.
set -o pipefail || true
guix package -A g | head -1 2> "$HOME/err1"
guix package -I | head -1 2> "$HOME/err2"
test "`cat "$HOME/err1" "$HOME/err2"`" = ""

# Make sure '-L' extends the package module search path.
mkdir "$module_dir"

cat > "$module_dir/foo.scm"<<EOF
(define-module (foo)
  #:use-module (guix packages)
  #:use-module (gnu packages emacs))

(define-public x
  (package (inherit emacs)
    (name "emacs-foo-bar")
    (version "42.77.0")))
EOF

guix package -A emacs-foo-bar -L "$module_dir" | grep 42
guix package -i emacs-foo-bar@42 -n -L "$module_dir"

# Same thing using the 'GUIX_PACKAGE_PATH' environment variable.
GUIX_PACKAGE_PATH="$module_dir"
export GUIX_PACKAGE_PATH
guix package -A emacs-foo-bar | grep 42
guix package -i emacs-foo-bar@42 -n

# Make sure GUIX_PACKAGE_PATH/'-L' takes precedence in case of duplicate packages.
cat > "$module_dir/bar.scm"<<EOF
(define-module (bar)
  #:use-module (guix packages))

(define-public hello
  (package (inherit (@@ (gnu packages base) hello))
    (synopsis "an overridden version of GNU hello")))
EOF

guix package -i hello -n 2>&1 | grep choosing.*bar.scm
( unset GUIX_PACKAGE_PATH; \
  guix package -i hello -n -L "$module_dir" 2>&1 | grep choosing.*bar.scm )

# Make sure patches that live under $GUIX_PACKAGE_PATH are found.
cat > "$module_dir/emacs.patch"<<EOF
This is a fake patch.
EOF
cat > "$module_dir/foo.scm"<<EOF
(define-module (foo)
  #:use-module (guix packages)
  #:use-module (gnu packages)
  #:use-module (gnu packages emacs))

(define-public x
  (package (inherit emacs)
    (source (origin (inherit (package-source emacs))
              (patches (list (search-patch "emacs.patch")))))
    (name "emacs-foo-bar-patched")
    (version "42.42.42")))

(define-public y
  (package (inherit emacs)
    (name "super-non-portable-emacs")
    (supported-systems '("foobar64-hurd"))))
EOF
guix package -i emacs-foo-bar-patched -n

# Same when -L is used.
( unset GUIX_PACKAGE_PATH;					\
  guix package -L "$module_dir" -i emacs-foo-bar-patched -n )

# Make sure installing from a file works.
cat > "$module_dir/package.scm"<<EOF
(use-modules (gnu))
(use-package-modules bootstrap)

%bootstrap-guile
EOF
guix package --bootstrap --install-from-file="$module_dir/package.scm"

# Make sure an error is raised if the file doesn't return a package.
cat > "$module_dir/package.scm"<<EOF
(use-modules (gnu packages base))

(define my-package coreutils)   ;returns *unspecified*
EOF
! guix package --bootstrap --install-from-file="$module_dir/package.scm"

rm "$module_dir/package.scm"

# This one should not show up in searches since it's no supported on the
# current system.
test "`guix package -A super-non-portable-emacs`" = ""
test "`guix package -s super-non-portable-emacs | grep ^systems:`" = "systems: "

# Don't upgrade packages marked for removal: <http://bugs.gnu.org/27262>.
guix package --bootstrap -p "$profile" -i guile-bootstrap

cat > "$module_dir/foo.scm"<<EOF
(define-module (foo)
  #:use-module (guix)
  #:use-module (gnu packages bootstrap))

(define-public x
  (package (inherit %bootstrap-guile) (version "42")))
EOF

guix package --bootstrap -p "$profile" -r guile-bootstrap -u guile
test ! -f "$profile/bin/guile"
guix package --bootstrap -p "$profile" --roll-back
test -f "$profile/bin/guile"
rm "$profile-2-link"

unset GUIX_PACKAGE_PATH

# Using 'GUIX_BUILD_OPTIONS'.
available="`guix package -A | sort`"
GUIX_BUILD_OPTIONS="--dry-run --no-grafts"
export GUIX_BUILD_OPTIONS

# Make sure $GUIX_BUILD_OPTIONS is not simply appended to the command-line,
# which would break 'guix package -A' and similar.
available2="`guix package -A | sort`"
test "$available2" = "$available"
guix package -I

# Restore '--no-grafts', which makes sure we don't end up building stuff when
# '--dry-run' is passed.
GUIX_BUILD_OPTIONS="--no-grafts"

# Install using the "imperative model", export a manifest, instantiate it, and
# make sure we get the same profile.
guix package --bootstrap -i guile-bootstrap --without-tests=foo
profile_directory="$(readlink -f "$default_profile")"
guix package --export-manifest > "$tmpfile"
grep 'without-tests.*foo' "$tmpfile"
guix package --rollback --bootstrap
guix package --bootstrap -m "$tmpfile"
test "$(readlink -f "$default_profile")" = "$profile_directory"
guix package --export-manifest > "$tmpfile.2nd"
cmp "$tmpfile" "$tmpfile.2nd"

rm -f "$tmpfile.2nd"
guix package --rollback --bootstrap

# Applying a manifest file.
cat > "$module_dir/manifest.scm"<<EOF
(use-package-modules bootstrap)

(packages->manifest (list %bootstrap-guile))
EOF
guix package --bootstrap -m "$module_dir/manifest.scm"
guix package -I | grep guile
test `guix package -I | wc -l` -eq 1

# Export a manifest, instantiate it, and make sure we get the same profile.
profile_directory="$(readlink -f "$default_profile")"
guix package --export-manifest > "$tmpfile"
guix package --rollback --bootstrap
guix package --bootstrap -m "$tmpfile"
test "$(readlink -f "$default_profile")" = "$profile_directory"

guix package --rollback --bootstrap

# Applying two manifests.
cat > "$module_dir/manifest2.scm"<<EOF
(use-modules (gnu packages bootstrap) (guix))
(define p (package (inherit %bootstrap-guile) (name "eliug")))
(packages->manifest (list p))
EOF
guix package --bootstrap \
     -m "$module_dir/manifest.scm" -m "$module_dir/manifest2.scm"
guix package -I | grep guile
guix package -I | grep eliug
test `guix package -I | wc -l` -eq 2
guix package --rollback --bootstrap

# Applying a manifest file with inferior packages.
cat > "$module_dir/manifest.scm"<<EOF
(use-modules (guix inferior))

(define i
  (open-inferior "$abs_top_srcdir" #:command "scripts/guix"))

(let ((guile (car (lookup-inferior-packages i "guile-bootstrap"))))
  (packages->manifest (list guile)))
EOF
guix package --bootstrap -m "$module_dir/manifest.scm"
guix package -I | grep guile
test `guix package -I | wc -l` -eq 1

# Error reporting.
cat > "$module_dir/manifest.scm"<<EOF
(use-package-modules bootstrap)
(packages->manifest
  (list %bootstrap-guile
        wonderful-package-that-does-not-exist))
EOF
if guix package --bootstrap -n -m "$module_dir/manifest.scm" \
	2> "$module_dir/stderr"
then false
else
    cat "$module_dir/stderr"
    grep "manifest.scm:[1-4]:.*wonderful-package.*: unbound variable" \
	 "$module_dir/stderr"
fi

# Verify that package outputs are included in search results.
rm -rf "$module_dir"
mkdir "$module_dir"
cat > "$module_dir/foo.scm"<<EOF
(define-module (foo)
  #:use-module (guix packages)
  #:use-module (guix build-system trivial))

(define-public dummy-package
  (package
    (name "dummy-package")
    (version "dummy-version")
    (outputs '("out" "dummy-output"))
    (source #f)
    ;; Without a real build system, the "guix package -s" command will fail.
    (build-system trivial-build-system)
    (synopsis "dummy-synopsis")
    (description "dummy-description")
    (home-page "https://dummy-home-page")
    (license #f)))
EOF
guix package -L "$module_dir" -s dummy-output > /tmp/out
test "`guix package -L "$module_dir" -s dummy-output | grep ^name:`" = "name: dummy-package"
rm -rf "$module_dir"

# Make sure we can see user profiles.
guix package --list-profiles | grep "$profile"
guix package --list-profiles | grep '\.guix-profile'

# Make sure we can properly lock a profile.
mkdir "$module_dir"
echo "(open-output-file \"$module_dir/ready\") (sleep 60)" \
     > "$module_dir/manifest.scm"
guix package -m "$module_dir/manifest.scm" -p "$module_dir/profile" &
pid=$!
while [ ! -f "$module_dir/ready" ] ; do sleep 0.5 ; done
if guix install emacs -p "$module_dir/profile"; then kill $pid; false; else true; fi
kill $pid


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com>
# Copyright © 2020 Konrad Hinsen <konrad.hinsen@fastmail.net>
#
# 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/>.

#
# Test the `guix repl' command-line utility.
#

guix repl --version

test_directory="`mktemp -d`"
export test_directory
trap 'chmod -Rf +w "$test_directory"; rm -rf "$test_directory"' EXIT

tmpfile="$test_directory/foo.scm"
rm -f "$tmpfile"
trap 'rm -f "$tmpfile"' EXIT

module_dir="t-guix-repl-$$"
mkdir "$module_dir"
trap 'rm -rf "$module_dir"' EXIT

cat > "$tmpfile"<<EOF
(use-modules (guix packages)
             (gnu packages base))

(format #t "~a\n" (package-name coreutils))
EOF

test "`guix repl "$tmpfile"`" = "coreutils"

# Make sure that the file can also be loaded when passed as a relative file
# name.
(cd "$(dirname "$tmpfile")"; test "$(guix repl "$(basename "$tmpfile")")" = "coreutils")

cat > "$module_dir/foo.scm"<<EOF
(define-module (foo)
  #:use-module (guix packages)
  #:use-module (gnu packages base))

(define-public dummy
  (package (inherit hello)
    (name "dummy")
    (version "42")
    (synopsis "dummy package")
    (description "dummy package. Only used for testing purposes.")))
EOF

cat > "$tmpfile"<<EOF
(use-modules (guix packages)
             (foo))

(format #t "~a\n" (package-version dummy))
EOF

test "`guix repl "$tmpfile" -L "$module_dir"`" = "42"

cat > "$tmpfile"<<EOF
(format #t "~a\n" (cdr (command-line)))
EOF

test "`guix repl -- "$tmpfile" -a b --input=foo.txt`" = "(-a b --input=foo.txt)"

cat > "$tmpfile"<<EOF
#!$(type -P env) -S guix repl --
!#
(format #t "~a\n" (cdr (command-line)))
EOF
chmod 755 $tmpfile

test "`"$tmpfile" -a b --input=foo.txt`" = "(-a b --input=foo.txt)"


code:
# GNU Guix --- Functional package management for GNU
# Copyright © 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <ludo@gnu.org>
# Copyright © 2017 Tobias Geerinckx-Rice <me@tobias.gr>
# Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
#
# 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/>.

#
# Test 'guix system', mostly error reporting.
#

set -e

guix system --version

tmpfile="t-guix-system-$$"
errorfile="t-guix-system-error-$$"

# Note: This directory is chosen outside $builddir so that relative file name
# canonicalization doesn't mess up with 'current-source-directory', used by
# 'local-file' ('load' forces 'relative' for
# %FILE-PORT-NAME-CANONICALIZATION.)
tmpdir="${TMPDIR:-/tmp}/t-guix-system-$$"
mkdir "$tmpdir"

trap 'rm -f "$tmpfile" "$errorfile" "$tmpdir"/*; rmdir "$tmpdir"' EXIT

# Reporting of syntax errors.

cat > "$tmpfile"<<EOF
;; This is line 1, and the next one is line 2.
   (operating-system)
;; The 'T' is at column 3.
EOF

if guix system vm "$tmpfile" 2> "$errorfile"
then
    # This must not succeed.
    exit 1
else
    cat "$errorfile"
    grep "$tmpfile:2:3:.*missing.* initializers" "$errorfile"
fi

cat > "$tmpfile"<<EOF
;; This is line 1, and the next one is line 2.
   (operating-system
;; This is line 3, and there is no closing paren!
EOF

if guix system vm "$tmpfile" 2> "$errorfile"
then
    # This must not succeed.
    exit 1
else
    cat "$errorfile"

    # Guile 3.0.6 gets line/column numbers for 'read-error' wrong
    # (zero-indexed): <https://bugs.gnu.org/48089>.
    grep "$tmpfile:4:1: missing closing paren" "$errorfile" || \
    grep "$tmpfile:3:0: missing closing paren" "$errorfile"
fi

# Reporting of module not found errors.

cat > "$tmpfile" <<EOF
;; Line 1.
(use-modules (gnu))
  (use-service-modules openssh)
EOF

if guix system build "$tmpfile" -n 2> "$errorfile"
then false
else
    grep "$tmpfile:3:2: .*module .*openssh.*not found" "$errorfile"
    grep "Try.*use-service-modules ssh" "$errorfile"
fi

cat > "$tmpfile" <<EOF
;; Line 1.
(use-modules (gnu))
  (use-package-modules qemu)
EOF

if guix system build "$tmpfile" -n 2> "$errorfile"
then false
else
    grep "$tmpfile:3:2: .*module .*qemu.*not found" "$errorfile"
    grep "Try.*use-package-modules virtualization" "$errorfile"
fi

# Reporting of unbound variables.

cat > "$tmpfile" <<EOF
(use-modules (gnu))                                   ; 1
(use-service-modules networking)                      ; 2

(operating-system                                     ; 4
  (host-name "antelope")                              ; 5
  (timezone "Europe/Paris")                           ; 6
  (locale "en_US.UTF-8")                              ; 7

  (bootloader (GRUB-config (target "/dev/sdX")))      ; 9
  (file-systems (cons (file-system
                        (device (file-system-label "root"))
                        (mount-point "/")
                        (type "ext4"))
                      %base-file-systems)))
EOF

if guix system build "$tmpfile" -n 2> "$errorfile"
then false
else
    if test "`guile -c '(display (effective-version))'`" = 3.0
    then
	# FIXME: With Guile 3.3.0 the error is reported on line 11.
	# See <https://bugs.gnu.org/38388>.
	grep "$tmpfile:[0-9]\+:[0-9]\+:.*GRUB-config.*[Uu]nbound variable" "$errorfile"
    elif 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]:[0-9]\+:.*GRUB-config.*[Uu]nbound variable" "$errorfile"
    else
	grep "$tmpfile:9:[0-9]\+:.*GRUB-config.*[Uu]nbound variable" "$errorfile"
    fi
fi

cat > "$tmpfile" <<EOF
(use-modules (gnu))                                    ; 1

(operating-system                                      ; 3
  (file-systems (cons (file-system                     ; 4
                        (device (file-system-label "root"))
                        (mount-point "/")              ; 6
                        (type "ext4"))))               ; 7 (!!)
                      %base-file-systems)
EOF

if guix system build "$tmpfile" -n 2> "$errorfile"
then false
else
    # Here '%base-file-systems' appears as if it were a field specified of the
    # enclosing 'operating-system' form due to parenthesis mismatch.
    grep "$tmpfile:3:[0-9]\+:.*%base-file-system.*invalid field specifier" \
	 "$errorfile"
fi

OS_BASE='
  (host-name "antelope")
  (timezone "Europe/Paris")
  (locale "en_US.UTF-8")

  (bootloader (bootloader-configuration
               (bootloader grub-bootloader)
               (target "/dev/sdX")))
  (file-systems (cons (file-system
                        (device (file-system-label "root"))
                        (mount-point "/")
                        (type "ext4"))
                      %base-file-systems))
'

# Reporting of duplicate service identifiers.

cat > "$tmpfile" <<EOF
(use-modules (gnu))
(use-service-modules networking)

(operating-system
  $OS_BASE
  (services (cons* (service dhcp-client-service-type)
                   (service dhcp-client-service-type) ;twice!
                   %base-services)))
EOF

if guix system vm "$tmpfile" 2> "$errorfile"
then
    # This must not succeed.
    exit 1
else
    grep "service 'networking'.*more than once" "$errorfile"
fi

# Reporting unmet shepherd requirements.

cat > "$tmpfile" <<EOF
(use-modules (gnu) (gnu services shepherd))
(use-service-modules networking)

(define buggy-service-type
  (shepherd-service-type
    'buggy
    (lambda _
      (shepherd-service
        (provision '(buggy!))
        (requirement '(does-not-exist))
        (start #t)))
    (description "Buggy.")))

(operating-system
  $OS_BASE
  (services (cons (service buggy-service-type #t)
                  %base-services)))
EOF

if guix system build "$tmpfile" 2> "$errorfile"
then
    exit 1
else
    grep "service 'buggy!'.*'does-not-exist'.*not provided" "$errorfile"
fi

# Reporting inconsistent user accounts.

make_user_config ()
{
    cat > "$tmpfile" <<EOF
(use-modules (gnu))
(use-service-modules networking)

(operating-system
  (host-name "antelope")
  (timezone "Europe/Paris")
  (locale "en_US.UTF-8")

  (bootloader (bootloader-configuration
                (bootloader grub-bootloader)
                (target "/dev/sdX")))
  (file-systems (cons (file-system
                        (device (file-system-label "root"))
                        (mount-point "/")
                        (type "ext4"))
                      %base-file-systems))
  (users (list (user-account
                 (name "dave")
                 (home-directory "/home/dave")
                 (group "$1")
                 (supplementary-groups '("$2"))))))
EOF
}

make_user_config "users" "wheel"
guix system build "$tmpfile" -n       # succeeds

guix system build "$tmpfile" -d	      # succeeds
guix system build "$tmpfile" -d | grep '\.drv$'

guix system vm "$tmpfile" -d	      # succeeds
guix system vm "$tmpfile" -d | grep '\.drv$'

# Make sure the behavior is deterministic (<https://bugs.gnu.org/32652>).
drv1="`guix system vm "$tmpfile" -d`"
drv2="`guix system vm "$tmpfile" -d`"
test "$drv1" = "$drv2"
drv1="`guix system image -t iso9660 "$tmpfile" -d`"
drv2="`guix system image -t iso9660 "$tmpfile" -d`"
test "$drv1" = "$drv2"

# Check whether the graph commands work as expected.
guix system extension-graph "$tmpfile" | grep 'label = "file-systems"'
guix system shepherd-graph "$tmpfile" | grep 'label = "guix-daemon"'

make_user_config "group-that-does-not-exist" "users"
if guix system build "$tmpfile" -n 2> "$errorfile"
then false
else grep "primary group.*group-that-does-not-exist.*undeclared" "$errorfile"; fi

make_user_config "users" "group-that-does-not-exist"
if guix system build "$tmpfile" -n 2> "$errorfile"
then false
else grep "supplementary group.*group-that-does-not-exist.*undeclared" "$errorfile"; fi

# Try 'local-file' and relative file name resolution.

cat > "$tmpdir/config.scm"<<EOF
(use-modules (gnu))
(use-service-modules networking)

(operating-system
  $OS_BASE
  (services (cons (service tor-service-type
                           (tor-configuration
                             (config-file (local-file "my-torrc"))))
                  %base-services)))
EOF

cat > "$tmpdir/my-torrc"<<EOF
# This is an example file.
EOF

# In both cases 'my-torrc' should be properly resolved.
guix system build "$tmpdir/config.scm" -n
(cd "$tmpdir"; guix system build "config.scm" -n)

# Check that we get a warning when passing 'local-file' a non-literal relative
# file name.
cat > "$tmpdir/config.scm" <<EOF
(use-modules (guix))

(define (bad-local-file file)
  (local-file file))

(bad-local-file "whatever.scm")
EOF
! guix system build "$tmpdir/config.scm" -n
guix system build "$tmpdir/config.scm" -n 2>&1 | \
    grep "config\.scm:4:2: warning:.*whatever.*relative to current directory"

# Searching.
guix system search tor | grep "^name: tor"
guix system search tor | grep "^shepherdnames: tor"
guix system search anonym network | grep "^name: tor"
guix system search . > "$tmpdir/search"
test $(wc -l < "$tmpdir/search") -gt 500
rm "$tmpdir/search"

# Below, use -n (--dry-run) for the tests because if we actually tried to
# build these images, the commands would take hours to run in the worst case.

# Verify that the examples can be built.
for example in gnu/system/examples/*.tmpl; do
    if echo "$example" | grep hurd; then
        target="--target=i586-pc-gnu"
    else
        target=
    fi
    guix system -n disk-image $target "$example"
done

# Verify that the images can be built.
guix system -n vm gnu/system/examples/vm-image.tmpl
guix system -n image gnu/system/images/pinebook-pro.scm
guix system -n image -t qcow2 gnu/system/examples/vm-image.tmpl
guix system -n image -t iso9660 gnu/system/examples/bare-bones.tmpl
guix system -n docker-image gnu/system/examples/docker-image.tmpl

# Verify that at least the raw image type is available.
guix system --list-image-types | grep "raw"


code:
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
;;; Copyright © 2019 Robert Vollmert <rob@vllmrt.net>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;;
;;; 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-hackage)
  #:use-module (guix import cabal)
  #:use-module (guix import hackage)
  #:use-module (guix tests)
  #:use-module (srfi srfi-64)
  #:use-module (ice-9 match))

(define test-cabal-1
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
executable cabal
  build-depends:
    HTTP       >= 4000.2.5 && < 4000.3,
    mtl        >= 2.0      && < 3
")

(define test-cabal-2
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
executable cabal {
build-depends:
  HTTP       >= 4000.2.5 && < 4000.3,
  mtl        >= 2.0      && < 3
}
")

;; Check compiler implementation test with and without spaces.
(define test-cabal-3
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
library
  if impl(ghc >= 7.2 && < 7.6)
    Build-depends: ghc-a
  if impl(ghc>=7.2&&<7.6)
    Build-depends: ghc-b
  if impl(ghc == 7.8)
    Build-depends:
      HTTP       >= 4000.2.5 && < 4000.3,
      mtl        >= 2.0      && < 3
")

;; Check "-any", "-none" when name is different.
(define test-cabal-4
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
library
  if impl(ghcjs -any)
    Build-depends: ghc-a
  if impl(ghc>=7.2&&<7.6)
    Build-depends: ghc-b
  if impl(ghc == 7.8)
    Build-depends:
      HTTP       >= 4000.2.5 && < 4000.3,
      mtl        >= 2.0      && < 3
")

;; Check "-any", "-none".
(define test-cabal-5
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
library
  if impl(ghc == 7.8)
    Build-depends:
      HTTP       >= 4000.2.5 && < 4000.3,
  if impl(ghc -any)
    Build-depends: mtl        >= 2.0      && < 3
  if impl(ghc>=7.2&&<7.6)
    Build-depends: ghc-b
")

;; Check "custom-setup".
(define test-cabal-6
  "name: foo
build-type: Custom
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
custom-setup
  setup-depends: base >= 4.7 && < 5,
                 Cabal >= 1.24,
                 haskell-gi == 0.21.*
library
  if impl(ghc>=7.2&&<7.6)
    Build-depends: ghc-b
  if impl(ghc == 7.8)
    Build-depends:
      HTTP       >= 4000.2.5 && < 4000.3,
      mtl        >= 2.0      && < 3
")

;; A fragment of a real Cabal file with minor modification to check precedence
;; of 'and' over 'or', missing final newline, spaces between keywords and
;; parentheses and between key and column.
(define test-read-cabal-1
  "name: test-me
library
  -- Choose which library versions to use.
  if flag(base4point8)
    Build-depends: base >= 4.8 && < 5
  else
    if flag(base4)
      Build-depends: base >= 4 && < 4.8
    else
      if flag(base3)
        Build-depends: base >= 3 && < 4
      else
        Build-depends: base < 3
  if flag(base4point8) || flag (base4) && flag(base3)
    Build-depends: random
  Build-depends : containers

  -- Modules that are always built.
  Exposed-Modules:
    Test.QuickCheck.Exception")

(test-begin "hackage")

(define-syntax-rule (define-package-matcher name pattern)
  (define* (name obj)
    (match obj
      (pattern #t)
      (x       (pk 'fail x #f)))))

(define-package-matcher match-ghc-foo
  ('package
    ('name "ghc-foo")
    ('version "1.0.0")
    ('source
     ('origin
       ('method 'url-fetch)
       ('uri ('string-append
              "https://hackage.haskell.org/package/foo/foo-"
              'version
              ".tar.gz"))
       ('sha256
        ('base32
         (? string? hash)))))
    ('build-system 'haskell-build-system)
    ('inputs
     ('quasiquote
      (("ghc-http" ('unquote 'ghc-http)))))
    ('home-page "http://test.org")
    ('synopsis (? string?))
    ('description (? string?))
    ('license 'license:bsd-3)))

(define* (eval-test-with-cabal test-cabal matcher #:key (cabal-environment '()))
  (define port (open-input-string test-cabal))
  (matcher (hackage->guix-package "foo" #:port port #:cabal-environment cabal-environment)))

(test-assert "hackage->guix-package test 1"
  (eval-test-with-cabal test-cabal-1 match-ghc-foo))

(test-assert "hackage->guix-package test 2"
  (eval-test-with-cabal test-cabal-2 match-ghc-foo))

(test-assert "hackage->guix-package test 3"
  (eval-test-with-cabal test-cabal-3 match-ghc-foo
                        #:cabal-environment '(("impl" . "ghc-7.8"))))

(test-assert "hackage->guix-package test 4"
  (eval-test-with-cabal test-cabal-4 match-ghc-foo
                        #:cabal-environment '(("impl" . "ghc-7.8"))))

(test-assert "hackage->guix-package test 5"
  (eval-test-with-cabal test-cabal-5 match-ghc-foo
                        #:cabal-environment '(("impl" . "ghc-7.8"))))

(define-package-matcher match-ghc-foo-6
  ('package
    ('name "ghc-foo")
    ('version "1.0.0")
    ('source
     ('origin
       ('method 'url-fetch)
       ('uri ('string-append
              "https://hackage.haskell.org/package/foo/foo-"
              'version
              ".tar.gz"))
       ('sha256
        ('base32
         (? string? hash)))))
    ('build-system 'haskell-build-system)
    ('inputs
     ('quasiquote
      (("ghc-b" ('unquote 'ghc-b))
       ("ghc-http" ('unquote 'ghc-http)))))
    ('native-inputs
     ('quasiquote
      (("ghc-haskell-gi" ('unquote 'ghc-haskell-gi)))))
    ('home-page "http://test.org")
    ('synopsis (? string?))
    ('description (? string?))
    ('license 'license:bsd-3)))

(test-assert "hackage->guix-package test 6"
  (eval-test-with-cabal test-cabal-6 match-ghc-foo-6))

;; Check multi-line layouted description.
(define test-cabal-multiline-layout
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description:   first line
               second line
license: BSD3
executable cabal
  build-depends:
    HTTP       >= 4000.2.5 && < 4000.3,
    mtl        >= 2.0      && < 3
")

(test-assert "hackage->guix-package test multiline desc (layout)"
  (eval-test-with-cabal test-cabal-multiline-layout match-ghc-foo))

;; Check multi-line braced description.
(define test-cabal-multiline-braced
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: {
first line
second line
}
license: BSD3
executable cabal
  build-depends:
    HTTP       >= 4000.2.5 && < 4000.3,
    mtl        >= 2.0      && < 3
")

(test-assert "hackage->guix-package test multiline desc (braced)"
  (eval-test-with-cabal test-cabal-multiline-braced match-ghc-foo))

;; Check mixed layout. Compare e.g. warp.
(define test-cabal-mixed-layout
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
executable cabal
    build-depends:
      HTTP       >= 4000.2.5 && < 4000.3,
      mtl        >= 2.0      && < 3
  ghc-options: -Wall
")

;; Fails: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=35743
(test-expect-fail 1)
(test-assert "hackage->guix-package test mixed layout"
  (eval-test-with-cabal test-cabal-mixed-layout match-ghc-foo))

;; Check flag executable. Compare e.g. darcs.
(define test-cabal-flag-executable
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
flag executable
  description: Build executable
  default:     True
executable cabal
  if !flag(executable)
    buildable: False
  else
    buildable: True

  build-depends:
    HTTP       >= 4000.2.5 && < 4000.3,
    mtl        >= 2.0      && < 3
")

;; Fails: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25138
(test-expect-fail 1)
(test-assert "hackage->guix-package test flag executable"
  (eval-test-with-cabal test-cabal-flag-executable match-ghc-foo))

;; Check Hackage Cabal revisions.
(define test-cabal-revision
  "name: foo
version: 1.0.0
x-revision: 2
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
executable cabal
  build-depends:
    HTTP       >= 4000.2.5 && < 4000.3,
    mtl        >= 2.0      && < 3
")

(define-package-matcher match-ghc-foo-revision
  ('package
    ('name "ghc-foo")
    ('version "1.0.0")
    ('source
     ('origin
       ('method 'url-fetch)
       ('uri ('string-append
              "https://hackage.haskell.org/package/foo/foo-"
              'version
              ".tar.gz"))
       ('sha256
        ('base32
         (? string? hash)))))
    ('build-system 'haskell-build-system)
    ('inputs
     ('quasiquote
      (("ghc-http" ('unquote 'ghc-http)))))
    ('arguments
     ('quasiquote
      ('#:cabal-revision
       ("2" "0xxd88fb659f0krljidbvvmkh9ppjnx83j0nqzx8whcg4n5qbyng"))))
    ('home-page "http://test.org")
    ('synopsis (? string?))
    ('description (? string?))
    ('license 'license:bsd-3)))

(test-assert "hackage->guix-package test cabal revision"
  (eval-test-with-cabal test-cabal-revision match-ghc-foo-revision))

(test-assert "read-cabal test 1"
  (match (call-with-input-string test-read-cabal-1 read-cabal)
    ((("name" ("test-me"))
      ('section 'library
                (('if ('flag "base4point8")
                      (("build-depends" ("base >= 4.8 && < 5")))
                      (('if ('flag "base4")
                            (("build-depends" ("base >= 4 && < 4.8")))
                            (('if ('flag "base3")
                                  (("build-depends" ("base >= 3 && < 4")))
                                  (("build-depends" ("base < 3"))))))))
                 ('if ('or ('flag "base4point8")
                           ('and ('flag "base4") ('flag "base3")))
                      (("build-depends" ("random")))
                      ())
                 ("build-depends" ("containers"))
                 ("exposed-modules" ("Test.QuickCheck.Exception")))))
     #t)
    (x (pk 'fail x #f))))

(define test-cabal-import
  "name: foo
version: 1.0.0
homepage: http://test.org
synopsis: synopsis
description: description
license: BSD3
common commons
  build-depends:
    HTTP       >= 4000.2.5 && < 4000.3,
    mtl        >= 2.0      && < 3

executable cabal
  import: commons
")

(define-package-matcher match-ghc-foo-import
  ('package
    ('name "ghc-foo")
    ('version "1.0.0")
    ('source
     ('origin
       ('method 'url-fetch)
       ('uri ('string-append
              "https://hackage.haskell.org/package/foo/foo-"
              'version
              ".tar.gz"))
       ('sha256
        ('base32
         (? string? hash)))))
    ('build-system 'haskell-build-system)
    ('inputs
     ('quasiquote
      (("ghc-http" ('unquote 'ghc-http)))))
    ('home-page "http://test.org")
    ('synopsis (? string?))
    ('description (? string?))
    ('license 'license:bsd-3)))

(test-assert "hackage->guix-package test cabal import"
  (eval-test-with-cabal test-cabal-import match-ghc-foo-import))

(test-end "hackage")


code:
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015, 2017 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2016 Ben Woodcroft <donttrustben@gmail.com>
;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net>
;;;
;;; 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-import-utils)
  #:use-module (guix tests)
  #:use-module (guix import utils)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix packages)
  #:use-module (guix build-system)
  #:use-module (gnu packages)
  #:use-module (srfi srfi-64)
  #:use-module (ice-9 match))

(test-begin "import-utils")

(test-equal "beautify-description: use double spacing"
  "This is a package.  It is great.  Trust me Mr.  Hendrix."
  (beautify-description
   "This is a package. It is great. Trust me Mr. Hendrix."))

(test-equal "beautify-description: transform fragment into sentence"
  "This package provides a function to establish world peace"
  (beautify-description "A function to establish world peace"))

(test-equal "license->symbol"
  'license:lgpl2.0
  (license->symbol license:lgpl2.0))

(test-equal "recursive-import"
  '((package                         ;package expressions in topological order
      (name "bar"))
    (package
      (name "foo")
      (inputs `(("bar" ,bar)))))
  (recursive-import "foo"
                    #:repo 'repo
                    #:repo->guix-package
                    (match-lambda*
                      (("foo" #:version #f #:repo 'repo)
                       (values '(package
                                  (name "foo")
                                  (inputs `(("bar" ,bar))))
                               '("bar")))
                      (("bar" #:version #f #:repo 'repo)
                       (values '(package
                                  (name "bar"))
                               '())))
                    #:guix-name identity))

(test-assert "alist->package with simple source"
  (let* ((meta '(("name" . "hello")
                 ("version" . "2.10")
                 ("source" .
                  ;; Use a 'file://' URI so that we don't cause a download.
                  ,(string-append "file://"
                                  (search-path %load-path "guix.scm")))
                 ("build-system" . "gnu")
                 ("home-page" . "https://gnu.org")
                 ("synopsis" . "Say hi")
                 ("description" . "This package says hi.")
                 ("license" . "GPL-3.0+")))
         (pkg (alist->package meta)))
    (and (package? pkg)
         (license:license? (package-license pkg))
         (build-system? (package-build-system pkg))
         (origin? (package-source pkg)))))

(test-assert "alist->package with explicit source"
  (let* ((meta '(("name" . "hello")
                 ("version" . "2.10")
                 ("source" . (("method" . "url-fetch")
                              ("uri"    . "mirror://gnu/hello/hello-2.10.tar.gz")
                              ("sha256" .
                               (("base32" .
                                 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))))
                 ("build-system" . "gnu")
                 ("home-page" . "https://gnu.org")
                 ("synopsis" . "Say hi")
                 ("description" . "This package says hi.")
                 ("license" . "GPL-3.0+")))
         (pkg (alist->package meta)))
    (and (package? pkg)
         (license:license? (package-license pkg))
         (build-system? (package-build-system pkg))
         (origin? (package-source pkg))
         (equal? (origin-sha256 (package-source pkg))
                 (base32 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))))

(test-equal "alist->package with false license"  ;<https://bugs.gnu.org/30470>
  'license-is-false
  (let* ((meta '(("name" . "hello")
                 ("version" . "2.10")
                 ("source" . (("method" . "url-fetch")
                              ("uri"    . "mirror://gnu/hello/hello-2.10.tar.gz")
                              ("sha256" .
                               (("base32" .
                                 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))))
                 ("build-system" . "gnu")
                 ("home-page" . "https://gnu.org")
                 ("synopsis" . "Say hi")
                 ("description" . "This package says hi.")
                 ("license" . #f))))
    ;; Note: Use 'or' because comparing with #f otherwise succeeds when
    ;; there's an exception instead of an actual #f.
    (or (package-license (alist->package meta))
        'license-is-false)))

(test-equal "alist->package with SPDX license name 1/2"  ;<https://bugs.gnu.org/45453>
  license:expat
  (let* ((meta '(("name" . "hello")
                 ("version" . "2.10")
                 ("source" . (("method" . "url-fetch")
                              ("uri"    . "mirror://gnu/hello/hello-2.10.tar.gz")
                              ("sha256" .
                               (("base32" .
                                 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))))
                 ("build-system" . "gnu")
                 ("home-page" . "https://gnu.org")
                 ("synopsis" . "Say hi")
                 ("description" . "This package says hi.")
                 ("license" . "expat"))))
    (package-license (alist->package meta))))

(test-equal "alist->package with SPDX license name 2/2"  ;<https://bugs.gnu.org/45453>
  license:expat
  (let* ((meta '(("name" . "hello")
                 ("version" . "2.10")
                 ("source" . (("method" . "url-fetch")
                              ("uri"    . "mirror://gnu/hello/hello-2.10.tar.gz")
                              ("sha256" .
                               (("base32" .
                                 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))))
                 ("build-system" . "gnu")
                 ("home-page" . "https://gnu.org")
                 ("synopsis" . "Say hi")
                 ("description" . "This package says hi.")
                 ("license" . "MIT"))))
    (package-license (alist->package meta))))

(test-equal "alist->package with dependencies"
  `(("gettext" ,(specification->package "gettext")))
  (let* ((meta '(("name" . "hello")
                 ("version" . "2.10")
                 ("source" . (("method" . "url-fetch")
                              ("uri"    . "mirror://gnu/hello/hello-2.10.tar.gz")
                              ("sha256" .
                               (("base32" .
                                 "0ssi1wpaf7plaswqqjwigppsg5fyh99vdlb9kzl7c9lng89ndq1i")))))
                 ("build-system" . "gnu")
                 ("home-page" . "https://gnu.org")
                 ("synopsis" . "Say hi")
                 ("description" . "This package says hi.")
                                                  ;
                 ;; Note: As with Guile-JSON 3.x, JSON arrays are represented
                 ;; by vectors.
                 ("native-inputs" . #("gettext"))

                 ("license" . #f))))
    (package-native-inputs (alist->package meta))))

(test-end "import-utils")