# file      : tests/pkg-configure.testscript
# license   : MIT; see accompanying LICENSE file

# Here we test both pkg-configure and pkg-disfigure commands.
#

.include common.testscript auth.testscript config.testscript remote.testscript

# Source repository:
#
# pkg-configure
# |-- hello
# |   |-- libhello-1.0.0.tar.gz
# |   `-- repositories.manifest
# |-- libhello-1.0.0
# |   |-- build
# |   |   |-- bootstrap.build
# |   |   |-- export.build
# |   |   `-- root.build
# |   |-- buildfile
# |   |-- hello
# |   |   |-- buildfile
# |   |   |-- export
# |   |   |-- hello
# |   |   `-- hello.cxx
# |   |-- INSTALL
# |   |-- manifest
# |   |-- tests
# |   |   |-- build
# |   |   |   |-- bootstrap.build
# |   |   |   `-- root.build
# |   |   |-- buildfile
# |   |   `-- test
# |   |       |-- buildfile
# |   |       |-- driver.cxx
# |   |       `-- test.out
# |   `-- version
# |
# |-- t8a (see pkg-build for details)
# |
# `-- stable
#     |-- libbar-1.0.0.tar.gz -> libfoo
#     |-- libbar-1.1.0.tar.gz -> libfoo >= 1.1.0
#     |-- libbar-1.2.0.tar.gz -> libfoo >= 1.1.0, libfox | libfoo >= 1.2.0
#     |-- libbar-1.3.0.tar.gz -> libfox | libfoo <= 1.1.0,
#     |                          libfix | libfoo >= 1.1.0
#     |-- libfoo-1.0.0.tar.gz
#     |-- libfoo-1.1.0.tar.gz
#     |-- libfoo-1.2.0.tar.gz
#     `-- repositories.manifest

# Prepare repositories used by tests if running in the local mode.
#
+if! $remote
  rep_create += 2>!

  # Create the signed 'hello' repository.
  #
  cp -r $src/hello $out/hello
  cat <<<$cert_manifest >+$out/hello/repositories.manifest

  $rep_create --key $key $out/hello &$out/hello/packages.manifest \
                                    &$out/hello/signature.manifest

  # Create the 'stable' repository.
  #
  cp -r $src/stable $out/stable
  $rep_create $out/stable &$out/stable/packages.manifest

  cp -r $src/t8a $out/t8a && $rep_create $out/t8a &$out/t8a/packages.manifest
end

test.arguments += config.cxx=$quote($recall($cxx.path) $cxx.config.mode)

pkg_disfigure += -d cfg
pkg_fetch     += -d cfg 2>!
pkg_purge     += -d cfg
pkg_status    += -d cfg
pkg_unpack    += -d cfg 2>!
rep_add       += -d cfg 2>!
rep_fetch     += -d cfg --auth all 2>!

posix = ($cxx.target.class != 'windows')

+if $posix
  id -u | set uid
end

: no-name
:
$clone_cfg;
$* 2>>EOE != 0
  error: package name argument expected
    info: run 'bpkg help pkg-configure' for more information
  EOE

: var-no-name
:
$clone_cfg;
$* "config.dist.root=$~/opt" 2>>EOE != 0
  error: package name argument expected
    info: run 'bpkg help pkg-configure' for more information
  EOE

: unexpected-arg
:
$clone_cfg;
$* libhello libhello 2>>EOE != 0
  error: unexpected argument 'libhello'
  EOE

: fetched
:
{
  +$clone_cfg
  +$rep_add $rep/hello
  +$rep_fetch --trust $cert_fp &cfg/.bpkg/certs/**

  : no-such-package
  :
  $clone_cfg;
  $* libhello1 2>>/EOE != 0
    error: package libhello1 does not exist in configuration cfg/
    EOE

  : disfigure
  {
    : no-name
    :
    $clone_root_cfg;
    $pkg_disfigure 2>>EOE != 0
      error: package name argument expected
        info: run 'bpkg help pkg-disfigure' for more information
      EOE

    : no-such-package
    :
    $clone_root_cfg;
    $pkg_disfigure libhello1 2>>/EOE != 0
      error: package libhello1 does not exist in configuration cfg/
      EOE
  }

  : wrong-state
  :
  {
    $clone_cfg && $pkg_fetch libhello/1.0.0;

    $* libhello 2>>EOE != 0;
      error: package libhello is fetched
        info: expected it to be unpacked
      EOE

    $pkg_disfigure libhello 2>>EOE != 0;
      error: package libhello is fetched
        info: expected it to be configured
      EOE

    $pkg_purge libhello 2>'purged libhello/1.0.0'
  }

  : src-eq-out
  :
  {
    $clone_cfg;
    $pkg_fetch libhello/1.0.0 && $pkg_unpack libhello;

    $*             libhello 2>'configured libhello/1.0.0';
    $pkg_status    libhello 1>'libhello configured 1.0.0';
    $pkg_disfigure libhello 2>'disfigured libhello/1.0.0';
    $pkg_status    libhello 1>'libhello unpacked 1.0.0';

    $pkg_purge     libhello       2>'purged libhello/1.0.0';
    $pkg_status    libhello/1.0.0 1>'libhello available 1.0.0'
  }
}

: src-ne-out
:
{
  $clone_cfg && $pkg_unpack -e $src/libhello-1.0.0;

  $*             libhello 2>'configured libhello/1.0.0';
  $pkg_status    libhello 1>'libhello configured 1.0.0';
  $pkg_disfigure libhello 2>'disfigured libhello/1.0.0';
  $pkg_status    libhello 1>'libhello unpacked 1.0.0';

  $pkg_purge  libhello       2>'purged libhello/1.0.0';
  $pkg_status libhello       1>'libhello unknown';
  test -d cfg/libhello-1.0.0 == 1
}

: out-exists-disfigure
:
{
  $clone_cfg && $pkg_unpack -e $src/libhello-1.0.0;

  $* libhello 2>'configured libhello/1.0.0';
  touch cfg/libhello/stray &!cfg/libhello/stray;

  $pkg_disfigure libhello 2>'disfigured libhello/1.0.0';

  $pkg_status libhello/1.0.0 >'libhello unpacked 1.0.0';

  $pkg_purge -f libhello       2>'purged libhello/1.0.0';
  $pkg_status   libhello/1.0.0 1>'libhello unknown 1.0.0'
}

: broken
:
if ($posix && "$uid" != '0')
{
  : disfigure-failed
  :
  {
    $clone_root_cfg && $pkg_unpack -e $src/libhello-1.0.0;

    $* libhello 2>'configured libhello/1.0.0';
    chmod 555 cfg/libhello;

    $pkg_disfigure libhello 2>>/~%EOE% != 0;
      %error: unable to remove directory cfg/libhello/.+%
      info: package libhello is now broken; use 'pkg-purge' to remove
      EOE

    $pkg_status libhello >'libhello broken 1.0.0';

    chmod 755 cfg/libhello;
    rm -r cfg/libhello;
    $pkg_purge -f libhello 2>'purged libhello/1.0.0';
    $pkg_status libhello >'libhello unknown'
  }

  : configure-failed
  :
  : Note that pkg-configure in case of build2 process failure implicitly
  : performs pkg-disfigure, that succeeds.
  :
  {
    $clone_root_cfg && $pkg_unpack -e $src/libhello-1.0.0;
    mkdir -p cfg/libhello/build &!cfg/libhello/ &!cfg/libhello/build/;
    chmod 555 cfg/libhello/build;

    $* libhello 2>>/~%EOE% != 0;
      %error: unable to create directory cfg/libhello/build/.+%
      EOE

    $pkg_status libhello >'libhello unpacked 1.0.0'
  }

  : configure-disfigure-failed
  :
  : Note that pkg-configure in case of build2 process failure implicitly
  : performs pkg-disfigure, that also fails.
  :
  {
    $clone_root_cfg && $pkg_unpack -e $src/libhello-1.0.0;
    mkdir -p cfg/libhello/build &!cfg/libhello/ &!cfg/libhello/build/;
    chmod 555 cfg/libhello cfg/libhello/build;

    $* libhello 2>>/~%EOE% != 0;
      %error: unable to create directory cfg/libhello/build/.+%
      %error: unable to remove directory cfg/libhello/.+%
      info: package libhello is now broken; use 'pkg-purge' to remove
      EOE

    $pkg_status libhello >'libhello broken 1.0.0';

    chmod 755 cfg/libhello cfg/libhello/build;
    rm -r cfg/libhello;
    $pkg_purge -f libhello 2>'purged libhello/1.0.0';
    $pkg_status libhello >'libhello unknown'
  }
}

: dependency-management
:
{
  # Remove the config.cxx variable override to avoid the 'dropping no longer
  # used variable' warning.
  #
  test.arguments = $regex.filter_out_match($test.arguments, 'config.cxx=.*')

  +$clone_cfg && $rep_add $rep/stable && $rep_fetch --trust-yes

  : still-has-deps
  :
  {
    $clone_cfg;
    $pkg_fetch libbar/1.0.0 && $pkg_unpack libbar;

    $* libbar 2>>EOE != 0;
      error: unable to satisfy dependency on libfoo
      EOE

    $pkg_status libbar/1.0.0  1>'libbar unpacked 1.0.0';
    $pkg_fetch  libfoo/1.0.0;
    $pkg_unpack libfoo;

    $* libbar 2>>EOE != 0;
      error: unable to satisfy dependency on libfoo
      EOE

    $* libfoo 2>'configured libfoo/1.0.0';
    $* libbar 2>'configured libbar/1.0.0';

    $pkg_disfigure libfoo 2>>EOE != 0;
      error: package libfoo still has dependents:
        info: package libbar
      EOE

    $pkg_disfigure libbar 2>'disfigured libbar/1.0.0';
    $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';

    $pkg_purge libbar 2>'purged libbar/1.0.0';
    $pkg_purge libfoo 2>'purged libfoo/1.0.0'
  }

  : no-package-satisfy
  :
  {
    $clone_cfg;
    $pkg_fetch libfoo/1.0.0 && $pkg_unpack libfoo;

    $*          libfoo        2>'configured libfoo/1.0.0';
    $pkg_fetch  libbar/1.1.0;
    $pkg_unpack libbar;

    $* libbar 2>>EOE != 0;
      error: unable to satisfy dependency on libfoo >= 1.1.0
      EOE

    $pkg_disfigure libfoo        2>'disfigured libfoo/1.0.0';
    $pkg_purge     libfoo        2>'purged libfoo/1.0.0';
    $pkg_fetch     libfoo/1.1.0;
    $pkg_unpack    libfoo;
    $*             libfoo        2>'configured libfoo/1.1.0';
    $*             libbar        2>'configured libbar/1.1.0';
    $pkg_disfigure libbar        2>'disfigured libbar/1.1.0';
    $pkg_disfigure libfoo        2>'disfigured libfoo/1.1.0';

    $pkg_purge libfoo 2>'purged libfoo/1.1.0';
    $pkg_purge libbar 2>'purged libbar/1.1.0'
  }

  : no-package-satisfy-alt
  :
  {
    $clone_cfg;
    $pkg_fetch libfoo/1.1.0 && $pkg_unpack libfoo;

    $*          libfoo        2>'configured libfoo/1.1.0';
    $pkg_fetch  libbar/1.2.0;
    $pkg_unpack libbar;

    $* libbar 2>>EOE != 0;
      error: unable to satisfy dependency on libfox | libfoo >= 1.2.0
      EOE

    $pkg_disfigure libfoo        2>'disfigured libfoo/1.1.0';
    $pkg_purge     libfoo        2>'purged libfoo/1.1.0';
    $pkg_fetch     libfoo/1.2.0;
    $pkg_unpack    libfoo;
    $*             libfoo        2>'configured libfoo/1.2.0';
    $*             libbar        2>'configured libbar/1.2.0';

    $pkg_disfigure libfoo 2>>EOE != 0;
      error: package libfoo still has dependents:
        info: package libbar on libfoo >= 1.2.0
      EOE

    $pkg_disfigure libbar 2>'disfigured libbar/1.2.0';
    $pkg_disfigure libfoo 2>'disfigured libfoo/1.2.0';

    $pkg_purge libfoo 2>'purged libfoo/1.2.0';
    $pkg_purge libbar 2>'purged libbar/1.2.0'
  }

  : incompatible-constraints
  :
  {
    $clone_cfg;
    $pkg_fetch libfoo/1.1.0 && $pkg_unpack libfoo;

    $*          libfoo        2>'configured libfoo/1.1.0';
    $pkg_fetch  libbar/1.3.0;
    $pkg_unpack libbar;

    $* libbar 2>>EOE != 0;
      error: multiple dependencies on package libfoo
        info: libfoo <= 1.1.0
        info: libfoo >= 1.1.0
      EOE

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';

    $pkg_purge libfoo 2>'purged libfoo/1.1.0';
    $pkg_purge libbar 2>'purged libbar/1.3.0'
  }
}

: keep-out
:
{
  : fallback
  :
  : Test that pkg-disfigure falls back to the external package output directory
  : removal if the source directory have gone.
  :
  {
    $clone_root_cfg;

    # Configure libhello as an external package.
    #
    cp --no-cleanup -r $src/libhello-1.0.0 ./libhello;
    $pkg_unpack -e ./libhello;
    $* libhello 2>!;

    rm -r ./libhello;
    $pkg_disfigure --keep-out libhello 2>'disfigured libhello/1.0.0';
    test -d cfg/libhello != 0
  }
}

: dependency-alternatives
:
{
  # Remove the config.cxx variable override to avoid the 'dropping no longer
  # used variable' warning.
  #
  test.arguments = $regex.filter_out_match($test.arguments, 'config.cxx=.*')

  +$clone_root_cfg && $rep_add $rep/t8a && $rep_fetch --trust-yes

  : multiple-dependencies
  :
  {
    $clone_cfg;

    $pkg_fetch foo/1.0.0 && $pkg_unpack foo;

    $pkg_fetch libbar/1.0.0 && $pkg_unpack libbar;
    $* libbar 2>!;

    # Make sure that dependent configuration fails if some of the alternative
    # dependencies is not configured.
    #
    $* foo 2>>EOE != 0;
      error: unable to satisfy dependency on {libbar ^1.0.0 libbaz ^1.0.0}
      EOE

    $pkg_fetch libbaz/1.0.0 && $pkg_unpack libbaz;
    $* libbaz 2>!;

    $* foo 2>'configured foo/1.0.0';

    $pkg_disfigure foo    2>!;
    $pkg_purge     foo    2>!;
    $pkg_disfigure libbaz 2>!;
    $pkg_purge     libbaz 2>!;
    $pkg_disfigure libbar 2>!;
    $pkg_purge     libbar 2>!
  }

  : reflect
  :
  {
    $clone_cfg;

    $pkg_fetch fox/1.0.0 && $pkg_unpack fox;
    $pkg_fetch libbaz/1.0.0 && $pkg_unpack libbaz;

    $* libbaz 2>!;

    $* fox 2>'configured fox/1.0.0';

    cat cfg/fox-1.0.0/build/config.build >>~%EOO%;
      %.*
      config.fox.backend = libbaz
      %.*
      EOO

    $pkg_disfigure fox    2>!;
    $pkg_purge     fox    2>!;
    $pkg_disfigure libbaz 2>!;
    $pkg_purge     libbaz 2>!
  }
}
