# file      : tests/pkg-build.test
# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
# license   : MIT; see accompanying LICENSE file

.include common.test config.test remote.test remote-git.test

# Source repository:
#
# pkg-build
# |-- libbar-1.0.0.tar.gz
# |-- libbaz-1.1.0.tar.gz
# |-- libfoo-0.0.1.tar.gz
# |-- libfoo-1.0.0.tar.gz
# |
# |-- libfoo-1.1.0
# |   |-- build
# |   |   `-- bootstrap.build
# |   |-- buildfile
# |   `-- manifest
# |
# |-- libfoo-1.1.0.tar.gz
# |-- libfoo-1.2.0.tar.gz
# |
# |-- t1
# |   |-- libfoo-1.0.0.tar.gz
# |   `-- repositories.manifest
# |
# |-- t2
# |   |-- libbar-1.0.0.tar.gz   -> libfoo
# |   |-- libfoo-1.0.0.tar.gz
# |   `-- repositories.manifest
# |
# |-- t3                        -> t2 (prerequisite)
# |   |-- libbaz-1.0.0.tar.gz   -> libbar
# |   |-- libfox-1.0.0.tar.gz
# |   `-- repositories.manifest
# |
# |-- t4a
# |   |-- libfoo-1.1.0.tar.gz
# |   `-- repositories.manifest
# |
# |-- t4b                       -> t4a (prerequisite)
# |   |-- libbar-1.1.0.tar.gz   -> libfoo == 1.1.0
# |   `-- repositories.manifest
# |
# |-- t4c                       -> t4b (prerequisite)
# |   |-- libbaz-1.1.0.tar.gz   -> libfoo, libbar
# |   |-- libfoo-1.0.0.tar.gz
# |   `-- repositories.manifest
# |
# |-- t4d                       -> t4c (complement)
# |   |-- libbiz-1.0.0.tar.gz   -> libfox, libfoo, libbaz
# |   |-- libfox-1.0.0.tar.gz
# |   `-- repositories.manifest
# |
# |-- t5
# |   |-- libbar-1.2.0.tar.gz
# |   `-- repositories.manifest
# |
# |-- libhello-1.0.0
# |   |-- build
# |   |   |-- bootstrap.build
# |   |   |-- export.build
# |   |   `-- root.build
# |   `-- *
# |
# `-- git
#     |-- libbar.git            -> style-basic.git (prerequisite)
#     |-- libbaz.git
#     `-- style-basic.git

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

  cp -r $src/t1  $out/t1  && $rep_create $out/t1  &$out/t1/packages.manifest
  cp -r $src/t2  $out/t2  && $rep_create $out/t2  &$out/t2/packages.manifest
  cp -r $src/t3  $out/t3  && $rep_create $out/t3  &$out/t3/packages.manifest
  cp -r $src/t4a $out/t4a && $rep_create $out/t4a &$out/t4a/packages.manifest
  cp -r $src/t4b $out/t4b && $rep_create $out/t4b &$out/t4b/packages.manifest
  cp -r $src/t4c $out/t4c && $rep_create $out/t4c &$out/t4c/packages.manifest
  cp -r $src/t4d $out/t4d && $rep_create $out/t4d &$out/t4d/packages.manifest
  cp -r $src/t5  $out/t5  && $rep_create $out/t5  &$out/t5/packages.manifest

  # Create git repositories.
  #
  $git_extract $src/git/style-basic.tar
  $git_extract $src/git/libbar.tar &$out_git/state0/***
  $git_extract $src/git/libbaz.tar &$out_git/state1/***
end

pkg_configure += -d cfg "config.cxx=$config.cxx" 2>!
pkg_disfigure += -d cfg
pkg_drop      += -d cfg --drop-prerequisite 2>!
pkg_fetch     += -d cfg 2>!
pkg_purge     += -d cfg
pkg_status    += -d cfg
pkg_unpack    += -d cfg 2>!
rep_add       += -d cfg 2>!
rep_remove    += -d cfg 2>!
rep_fetch     += -d cfg --auth all --trust-yes 2>!

: libfoo
:
: Test building different versions of libfoo.
:
{
  test.arguments += --print-only

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

  : unknown-package
  :
  $clone_root_cfg;
  $* libfoo 2>>/EOE != 0
    error: unknown package libfoo
      info: configuration cfg/ has no repositories
      info: use 'bpkg rep-add' to add a repository
    EOE

  : unknown-package-ver
  :
  $clone_root_cfg;
  $* libfoo/1.0.0 2>>/EOE != 0
    error: unknown package libfoo
      info: configuration cfg/ has no repositories
      info: use 'bpkg rep-add' to add a repository
    EOE

  : archive
  :
  $clone_root_cfg;
  $* $src/libfoo-1.1.0.tar.gz >'build libfoo/1.1.0'

  : dir
  :
  $clone_root_cfg;
  $* $src/libfoo-1.1.0/ >'build libfoo/1.1.0'

  : unpacked-dir
  :
  {
    $clone_root_cfg && $pkg_unpack -e $src/libfoo-1.1.0;

    $* libfoo        >'build libfoo/1.1.0';
    $* libfoo/1.1.0  >'build libfoo/1.1.0';
    $* libfoo libfoo >'build libfoo/1.1.0';

    $* libfoo libfoo/1.1.0 2>>EOE != 0;
      error: duplicate package libfoo
        info: first mentioned as libfoo
        info: second mentioned as libfoo/1.1.0
      EOE

    $* libfoo/1.1.0 libfoo 2>>EOE != 0;
      error: duplicate package libfoo
        info: first mentioned as libfoo/1.1.0
        info: second mentioned as libfoo
      EOE

    $* libfoo/1.1.0 libfoo/1.1.0 >'build libfoo/1.1.0';

    $* libfoo/1.0.0 2>>/EOE != 0;
      error: unknown package libfoo
        info: configuration cfg/ has no repositories
        info: use 'bpkg rep-add' to add a repository
      EOE

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

  : t1
  :
  {
    +$clone_root_cfg && $rep_add $rep/t1 && $rep_fetch

    : downgrade
    :
    {
      $clone_cfg && $pkg_unpack -e $src/libfoo-1.1.0;

      $* libfoo       >'build libfoo/1.1.0';
      $* libfoo/1.0.0 >'downgrade libfoo/1.0.0';

      $* libfoo/0.0.1 2>>EOE != 0;
        error: libfoo/0.0.1 is not available in source
          info: specify sys:libfoo/0.0.1 if it is available from the system
        EOE

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

    : upgrade
    :
    {
      $clone_cfg;
      $pkg_fetch -e $src/libfoo-0.0.1.tar.gz && $pkg_unpack libfoo;

      $* libfoo       >'upgrade libfoo/1.0.0';
      $* libfoo/0.0.1 >'build libfoo/0.0.1';

      $* libfoo/1.1.0 2>>EOE != 0;
        error: libfoo/1.1.0 is not available in source
          info: specify sys:libfoo/1.1.0 if it is available from the system
        EOE

      $pkg_purge libfoo 2>'purged libfoo/0.0.1'
    }

    : upgrade-failure
    :
    {
      $clone_cfg;

      $* libfoo       >'build libfoo/1.0.0';
      $* libfoo/1.0.0 >'build libfoo/1.0.0';

      $* libfoo/1.1.0 2>>EOE != 0
        error: libfoo/1.1.0 is not available in source
          info: specify sys:libfoo/1.1.0 if it is available from the system
        EOE
    }
  }
}

: libbar-libfoo
:
: Test building libbar that depends on libfoo.
:
{
  test.arguments += --print-only

  : unknown-prerequisite
  :
  $clone_root_cfg;
  $* $src/libbar-1.0.0.tar.gz 2>>EOE != 0
    error: unknown prerequisite libfoo of package libbar
    info: while satisfying libbar/1.0.0
    EOE

  : t2
  :
  {
    +$clone_root_cfg && $rep_add $rep/t2 && $rep_fetch

    : build-prerequisite
    :
    {
      $clone_cfg;

      $* libbar >>EOO;
        build libfoo/1.0.0 (required by libbar)
        build libbar/1.0.0
        EOO

      $* libbar libfoo >>EOO;
        build libfoo/1.0.0
        build libbar/1.0.0
        EOO

      $* libbar libfoo/1.0.0 >>EOO;
        build libfoo/1.0.0
        build libbar/1.0.0
        EOO

      $* libbar libfoo libbar/1.0.0 2>>EOE != 0;
        error: duplicate package libbar
          info: first mentioned as libbar
          info: second mentioned as libbar/1.0.0
        EOE

      $* libbar libfoo/1.1.0 2>>EOE != 0
        error: libfoo/1.1.0 is not available in source
          info: specify sys:libfoo/1.1.0 if it is available from the system
        EOE
    }

    : upgrade-prerequisite
    :
    {
      $clone_cfg;
      $pkg_fetch -e $src/libfoo-0.0.1.tar.gz && $pkg_unpack libfoo;

      $* libbar >>EOO;
        build libfoo/0.0.1 (required by libbar)
        build libbar/1.0.0
        EOO

      $* libbar libfoo >>EOO;
        upgrade libfoo/1.0.0
        build libbar/1.0.0
        EOO

      $* libbar libfoo/0.0.1 >>EOO;
        build libfoo/0.0.1
        build libbar/1.0.0
        EOO

      $pkg_purge libfoo 2>'purged libfoo/0.0.1'
    }

    : downgrade-prerequisite
    :
    {
      $clone_cfg && $pkg_unpack -e $src/libfoo-1.1.0;

      $* libbar >>EOO;
        build libfoo/1.1.0 (required by libbar)
        build libbar/1.0.0
        EOO

      $* libbar libfoo >>EOO;
        build libfoo/1.1.0
        build libbar/1.0.0
        EOO

      $* libbar libfoo/1.0.0 >>EOO;
        downgrade libfoo/1.0.0
        build libbar/1.0.0
        EOO

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

: libbaz-libbar
:
: Test building libbaz that depends on libbar; libbar is in prerequisite
: repository.
:
{
  test.arguments += --print-only

  : t3
  :
  {
    +$clone_root_cfg && $rep_add $rep/t3 && $rep_fetch

    : prerequisites-build-failure
    :
    : Fail to build packages that are only in prerequisite repository.
    :
    {
      $clone_cfg;

      $* libfoo 2>>EOE != 0;
        error: unknown package libfoo
        EOE

      $* libbar 2>>EOE != 0;
        error: unknown package libbar
        EOE

      $* libbaz libbar 2>>EOE != 0
        error: unknown package libbar
        EOE
    }

    : prerequisites-build
    :
    $clone_cfg;
    $* libbaz >>EOO
      build libfoo/1.0.0 (required by libbar)
      build libbar/1.0.0 (required by libbaz)
      build libbaz/1.0.0
      EOO

    : different-build-order
    :
    {
      +$clone_cfg && $rep_add $rep/t2 && $rep_fetch

      : fox-foo
      :
      $clone_cfg;
      $* libfox libfoo >>EOO
        build libfox/1.0.0
        build libfoo/1.0.0
        EOO

      : foo-fox
      :
      $clone_cfg;
      $* libfoo libfox >>EOO
        build libfoo/1.0.0
        build libfox/1.0.0
        EOO

      : baz-foo
      :
      $clone_cfg;
      $* libbaz libfoo >>EOO
        build libfoo/1.0.0
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        EOO

      : foo-baz
      :
      $clone_cfg;
      $* libfoo libbaz >>EOO
        build libfoo/1.0.0
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        EOO

      : baz-fox
      :
      $clone_cfg;
      $* libbaz libfox >>EOO
        build libfoo/1.0.0 (required by libbar)
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        build libfox/1.0.0
        EOO

      : fox-baz
      :
      $clone_cfg;
      $* libfox libbaz >>EOO
        build libfox/1.0.0
        build libfoo/1.0.0 (required by libbar)
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        EOO

      : fox-foo-baz
      :
      $clone_cfg;
      $* libfox libfoo libbaz >>EOO
        build libfox/1.0.0
        build libfoo/1.0.0
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        EOO

      : fox-baz-foo
      :
      $clone_cfg;
      $* libfox libbaz libfoo >>EOO
        build libfox/1.0.0
        build libfoo/1.0.0
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        EOO

      : foo-fox-baz
      :
      $clone_cfg;
      $* libfoo libfox libbaz >>EOO
        build libfoo/1.0.0
        build libfox/1.0.0
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        EOO

      : foo-baz-fox
      :
      $clone_cfg;
      $* libfoo libbaz libfox >>EOO
        build libfoo/1.0.0
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        build libfox/1.0.0
        EOO

      : baz-fox-foo
      :
      : This one is contradictory: baz before fox but fox before foo.
      :
      $clone_cfg;
      $* libbaz libfox libfoo >>EOO
        build libfox/1.0.0
        build libfoo/1.0.0
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        EOO

      : baz-foo-fox
      :
      $clone_cfg;
      $* libbaz libfoo libfox >>EOO
        build libfoo/1.0.0
        build libbar/1.0.0 (required by libbaz)
        build libbaz/1.0.0
        build libfox/1.0.0
        EOO

      : baz-foo-bar
      :
      $clone_cfg;
      $* libbaz libfoo libbar >>EOO
        build libfoo/1.0.0
        build libbar/1.0.0
        build libbaz/1.0.0
        EOO

      : baz-bar-foo
      :
      $clone_cfg;
      $* libbaz libbar libfoo >>EOO
        build libfoo/1.0.0
        build libbar/1.0.0
        build libbaz/1.0.0
        EOO
    }
  }
}

: libbaz-libfoo-libbar
:
: Test building libbaz that depends on libfoo and libbar; libbar depends on
: libfoo >= 1.1.0.
:
{
  test.arguments += --print-only

  : t4c
  :
  {
    +$clone_root_cfg && $rep_add $rep/t4c && $rep_fetch

    : baz
    :
    $clone_cfg;
    $* libbaz >>EOO
      build libfoo/1.1.0 (required by libbar libbaz)
      build libbar/1.1.0 (required by libbaz)
      build libbaz/1.1.0
      EOO

    : foo-baz
    :
    $clone_cfg;
    $* libfoo libbaz >>EOO
      build libfoo/1.1.0
      build libbar/1.1.0 (required by libbaz)
      build libbaz/1.1.0
      EOO

    : unable-satisfy
    :
    $clone_cfg;
    $* libfoo/1.0.0 libbaz 2>>EOE != 0
      error: unable to satisfy constraints on package libfoo
        info: libbar depends on (libfoo == 1.1.0)
        info: command line depends on (libfoo == 1.0.0)
        info: available libfoo/1.1.0
        info: available libfoo/1.0.0
        info: explicitly specify libfoo version to manually satisfy both constraints
      info: while satisfying libbar/1.1.0
      info: while satisfying libbaz/1.1.0
      EOE

    : not-available
    :
    $clone_cfg;
    $* libfoo/1.1.0 libbaz 2>>EOE != 0
      error: libfoo/1.1.0 is not available in source
        info: specify sys:libfoo/1.1.0 if it is available from the system
      EOE

    : upgrade-warning
    :
    {
      $clone_cfg;
      $pkg_fetch -e $src/libfoo-0.0.1.tar.gz && $pkg_unpack libfoo;

      $* libbaz >>EOO 2>>EOE;
        upgrade libfoo/1.1.0 (required by libbar libbaz)
        build libbar/1.1.0 (required by libbaz)
        build libbaz/1.1.0
        EOO
        warning: package libbar dependency on (libfoo == 1.1.0) is forcing upgrade of libfoo/0.0.1 to 1.1.0
        EOE

      $pkg_purge libfoo 2>'purged libfoo/0.0.1'
    }

    : downgrade-error
    :
    {
      $clone_cfg;
      $pkg_fetch -e $src/libfoo-1.2.0.tar.gz && $pkg_unpack libfoo;

      $* libbaz 2>>EOE != 0;
        error: package libbar dependency on (libfoo == 1.1.0) is forcing downgrade of libfoo/1.2.0 to 1.1.0
          info: explicitly request version downgrade to continue
        info: while satisfying libbar/1.1.0
        info: while satisfying libbaz/1.1.0
        EOE

      $rep_add $rep/t4a && $rep_fetch;

      $* libfoo/1.1.0 libbaz >>EOO;
        downgrade libfoo/1.1.0
        build libbar/1.1.0 (required by libbaz)
        build libbaz/1.1.0
        EOO

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

    : unable-downgrade
    :
    : Test that dependent prevents up/downgrade that would break dependency
    : constraints.
    :
    {
      $clone_cfg;
      $pkg_fetch libfoo/1.1.0 && $pkg_unpack libfoo && $pkg_configure libfoo;
      $pkg_fetch libbar/1.1.0 && $pkg_unpack libbar && $pkg_configure libbar;

      $* libfoo-1.2.0.tar.gz 2>>EOE != 0;
        error: unknown package libfoo-1.2.0.tar.gz
        EOE

      $* libfoo/1.0.0 2>>EOE != 0;
        error: unable to downgrade package libfoo/1.1.0 to 1.0.0
          info: because package libbar depends on (libfoo == 1.1.0)
          info: explicitly request up/downgrade of package libbar
          info: or explicitly specify package libfoo version to manually satisfy these constraints
        EOE

      $* libfoo/1.1.0 >'build libfoo/1.1.0';

      $pkg_disfigure libbar 2>'disfigured libbar/1.1.0';
      $pkg_purge     libbar 2>'purged libbar/1.1.0';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
    }
  }

  : dependent-reconfiguration
  :
  {
    +$clone_root_cfg

    +$pkg_fetch -e $src/libfoo-1.0.0.tar.gz && $pkg_unpack libfoo
    +$pkg_configure libfoo

    +$pkg_fetch -e $src/libbar-1.0.0.tar.gz && $pkg_unpack libbar
    +$pkg_configure libbar

    +$pkg_fetch -e $src/libbaz-1.1.0.tar.gz && $pkg_unpack libbaz
    +$pkg_configure libbaz

    +$rep_add $rep/t4a && $rep_add $rep/t4b && $rep_fetch

    : bar
    :
    $clone_cfg;
    $* libbar >>EOO 2>>EOE
      upgrade libfoo/1.1.0 (required by libbar libbaz)
      upgrade libbar/1.1.0
      reconfigure libbaz (dependent of libbar)
      EOO
      warning: package libbar dependency on (libfoo == 1.1.0) is forcing upgrade of libfoo/1.0.0 to 1.1.0
      EOE

    : foo
    :
    $clone_cfg;
    $* libfoo >>EOO
      upgrade libfoo/1.1.0
      reconfigure libbar (dependent of libfoo)
      reconfigure libbaz (dependent of libbar)
      EOO

    : foo-bar
    :
    $clone_cfg;
    $* libfoo libbar/1.0.0 >>EOO
      upgrade libfoo/1.1.0
      reconfigure/build libbar/1.0.0
      reconfigure libbaz (dependent of libbar)
      EOO

    : bar-foo
    :
    $clone_cfg;
    $* libbar/1.0.0 libfoo >>EOO
      upgrade libfoo/1.1.0
      reconfigure/build libbar/1.0.0
      reconfigure libbaz (dependent of libbar)
      EOO

    : baz-foo
    :
    $clone_cfg;
    $* libbaz libfoo >>EOO
      upgrade libfoo/1.1.0
      reconfigure libbar (dependent of libbaz libfoo)
      reconfigure/build libbaz/1.1.0
      EOO

    : baz-foo-1.0.0
    :
    $clone_cfg;
    $* libbaz libfoo/1.0.0 >>EOO
      build libfoo/1.0.0
      build libbaz/1.1.0
      EOO

    -$pkg_disfigure libbaz 2>'disfigured libbaz/1.1.0'
    -$pkg_purge     libbaz 2>'purged libbaz/1.1.0'

    -$pkg_disfigure libbar 2>'disfigured libbar/1.0.0'
    -$pkg_purge     libbar 2>'purged libbar/1.0.0'

    -$pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0'
    -$pkg_purge     libfoo 2>'purged libfoo/1.0.0'
  }
}

# Note that when we fetch a package from remote repository the bpkg stderr
# contains fetch program progress output, that comes prior the informational
# message.
#

: actual-build
:
{
  test.arguments += --yes

  : wth-prerequisites
  :
  {
    $clone_root_cfg && $rep_add $rep/t4c && $rep_fetch;

    $* libbaz 2>>~%EOE%;
      %.*
      %.*fetched libfoo/1.1.0%
      unpacked libfoo/1.1.0
      configured libfoo/1.1.0
      %.*
      %.*fetched libbar/1.1.0%
      unpacked libbar/1.1.0
      configured libbar/1.1.0
      %.*
      %.*fetched libbaz/1.1.0%
      unpacked libbaz/1.1.0
      configured libbaz/1.1.0
      %info: .+dir\{libbaz-1.1.0.\} is up to date%
      updated libbaz/1.1.0
      EOE

    $pkg_status libfoo/1.1.0 >'libfoo configured 1.1.0';
    $pkg_status libbar/1.1.0 >'libbar configured 1.1.0';
    $pkg_status libbaz/1.1.0 >'!libbaz configured 1.1.0';

    $pkg_disfigure libbaz 2>'disfigured libbaz/1.1.0';
    $pkg_purge     libbaz 2>'purged libbaz/1.1.0';

    $pkg_disfigure libbar 2>'disfigured libbar/1.1.0';
    $pkg_purge     libbar 2>'purged libbar/1.1.0';

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
  }

  : hold-fs-fetched
  :
  {
    : direct
    :
    {
      $clone_root_cfg;

      $* $src/libfoo-1.0.0.tar.gz 2>>~%EOE%;
        fetched libfoo/1.0.0
        unpacked libfoo/1.0.0
        configured libfoo/1.0.0
        %info: .+dir\{libfoo-1.0.0.\} is up to date%
        updated libfoo/1.0.0
        EOE

      $pkg_status libfoo >'!libfoo configured !1.0.0';

      $* $src/libfoo-1.1.0/ 2>>~%EOE%;
        disfigured libfoo/1.0.0
        using libfoo/1.1.0 (external)
        configured libfoo/1.1.0
        %info: .+dir\{libfoo.\} is up to date%
        updated libfoo/1.1.0
        EOE

      $pkg_status libfoo >'!libfoo configured !1.1.0';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
    }

    : pre-fetch
    :
    {
      $clone_root_cfg;
      $pkg_fetch -e $src/libfoo-1.0.0.tar.gz && $pkg_unpack libfoo;
      $pkg_configure libfoo;

      $pkg_status libfoo >'libfoo configured 1.0.0';

      $* libfoo 2>>~%EOE%;
        %info: .+dir\{libfoo-1.0.0.\} is up to date%
        updated libfoo/1.0.0
        EOE

      $pkg_status libfoo >'!libfoo configured 1.0.0';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.0.0'
    }
  }

  : hold-repo-fetched
  :
  {
    +$clone_root_cfg && $rep_add $rep/t4c && $rep_fetch

    : package-version
    :
    {
      $clone_cfg;

      $* libfoo 2>>~%EOE%;
        %.*
        %.*fetched libfoo/1.0.0%
        unpacked libfoo/1.0.0
        configured libfoo/1.0.0
        %info: .+dir\{libfoo-1.0.0.\} is up to date%
        updated libfoo/1.0.0
        EOE

      $pkg_status libfoo >'!libfoo configured 1.0.0 available [1.1.0]';

      $* libfoo/1.0.0 2>>~%EOE%;
        %info: .+dir\{libfoo-1.0.0.\} is up to date%
        updated libfoo/1.0.0
        EOE

      $pkg_status libfoo >'!libfoo configured !1.0.0 available [1.1.0]';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.0.0'
    }

    : version
    :
    {
      $clone_cfg;

      $* libfoo/1.0.0 2>>~%EOE%;
        %.*
        %.*fetched libfoo/1.0.0%
        unpacked libfoo/1.0.0
        configured libfoo/1.0.0
        %info: .+dir\{libfoo-1.0.0.\} is up to date%
        updated libfoo/1.0.0
        EOE

      $pkg_status libfoo >'!libfoo configured !1.0.0 available [1.1.0]';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.0.0'
    }

    : not-held
    :
    {
      $clone_cfg;

      $* libbaz 2>>~%EOE%;
        %.*
        %.*fetched libfoo/1.1.0%
        unpacked libfoo/1.1.0
        configured libfoo/1.1.0
        %.*
        %.*fetched libbar/1.1.0%
        unpacked libbar/1.1.0
        configured libbar/1.1.0
        %.*
        %.*fetched libbaz/1.1.0%
        unpacked libbaz/1.1.0
        configured libbaz/1.1.0
        %info: .+dir\{libbaz-1.1.0.\} is up to date%
        updated libbaz/1.1.0
        EOE

      $pkg_status libfoo >'libfoo configured 1.1.0';

      $pkg_disfigure libbaz 2>'disfigured libbaz/1.1.0';
      $pkg_purge     libbaz 2>'purged libbaz/1.1.0';

      $pkg_disfigure libbar 2>'disfigured libbar/1.1.0';
      $pkg_purge     libbar 2>'purged libbar/1.1.0';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
    }

    : forcing-upgrade-unheld
    :
    {
      $clone_cfg;

      $* libfoo 2>>~%EOE%;
        %.*
        %.*fetched libfoo/1.0.0%
        unpacked libfoo/1.0.0
        configured libfoo/1.0.0
        %info: .+dir\{libfoo-1.0.0.\} is up to date%
        updated libfoo/1.0.0
        EOE

      $pkg_status libfoo >'!libfoo configured 1.0.0 available [1.1.0]';

      $* libbaz 2>>~%EOE%;
        warning: package libbar dependency on (libfoo == 1.1.0) is forcing upgrade of libfoo/1.0.0 to 1.1.0
        disfigured libfoo/1.0.0
        %.*
        %.*fetched libfoo/1.1.0%
        unpacked libfoo/1.1.0
        configured libfoo/1.1.0
        %.*
        %.*fetched libbar/1.1.0%
        unpacked libbar/1.1.0
        configured libbar/1.1.0
        %.*
        %.*fetched libbaz/1.1.0%
        unpacked libbaz/1.1.0
        configured libbaz/1.1.0
        %info: .+dir\{libbaz-1.1.0.\} is up to date%
        updated libbaz/1.1.0
        EOE

      $pkg_status libfoo >'!libfoo configured 1.1.0';

      $pkg_disfigure libbaz 2>'disfigured libbaz/1.1.0';
      $pkg_purge     libbaz 2>'purged libbaz/1.1.0';

      $pkg_disfigure libbar 2>'disfigured libbar/1.1.0';
      $pkg_purge     libbar 2>'purged libbar/1.1.0';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
    }

    : forcing-upgrade-held
    :
    {
      $clone_cfg;

      $* libfoo/1.0.0 2>>~%EOE%;
        %.*
        %.*fetched libfoo/1.0.0%
        unpacked libfoo/1.0.0
        configured libfoo/1.0.0
        %info: .+dir\{libfoo-1.0.0.\} is up to date%
        updated libfoo/1.0.0
        EOE

      $pkg_status libfoo >'!libfoo configured !1.0.0 available [1.1.0]';

      $* libbaz 2>>EOE != 0;
        error: package libbar dependency on (libfoo == 1.1.0) is forcing upgrade of libfoo/1.0.0 to 1.1.0
          info: package version libfoo/1.0.0 is held
          info: explicitly request version upgrade to continue
        info: while satisfying libbar/1.1.0
        info: while satisfying libbaz/1.1.0
        EOE

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.0.0'
    }
  }

  : drop-prerequisites
  :
  {
    $clone_root_cfg && $rep_add $rep/t2 && $rep_fetch;

    $* libbar 2>>~%EOE%;
      %.*
      %.*fetched libfoo/1.0.0%
      unpacked libfoo/1.0.0
      configured libfoo/1.0.0
      %.*
      %.*fetched libbar/1.0.0%
      unpacked libbar/1.0.0
      configured libbar/1.0.0
      %info: .+dir\{libbar-1.0.0.\} is up to date%
      updated libbar/1.0.0
      EOE

    $pkg_status libfoo >'libfoo configured 1.0.0';
    $pkg_status libbar >'!libbar configured 1.0.0';

    $rep_add $rep/t5 && $rep_fetch;

    $* libbar 2>>~%EOE%;
      disfigured libbar/1.0.0
      %.*
      %.*fetched libbar/1.2.0%
      unpacked libbar/1.2.0
      configured libbar/1.2.0
      disfigured libfoo
      purged libfoo
      %info: .+dir\{libbar-1.2.0.\} is up to date%
      updated libbar/1.2.0
      EOE

    $pkg_status libfoo >'libfoo available 1.0.0';
    $pkg_status libbar >'!libbar configured 1.2.0';

    $* libbar/1.0.0 libfoo 2>>~%EOE%;
      disfigured libbar/1.2.0
      %.*
      %.*fetched libfoo/1.0.0%
      unpacked libfoo/1.0.0
      configured libfoo/1.0.0
      %.*
      %.*fetched libbar/1.0.0%
      unpacked libbar/1.0.0
      configured libbar/1.0.0
      %info: .+dir\{libfoo-1.0.0.\} is up to date%
      %info: .+dir\{libbar-1.0.0.\} is up to date%
      updated libfoo/1.0.0
      updated libbar/1.0.0
      EOE

    $pkg_status libfoo >'!libfoo configured 1.0.0';
    $pkg_status libbar >'!libbar configured !1.0.0 available 1.2.0';

    $* libbar 2>>~%EOE%;
      disfigured libbar/1.0.0
      %.*
      %.*fetched libbar/1.2.0%
      unpacked libbar/1.2.0
      configured libbar/1.2.0
      %info: .+dir\{libbar-1.2.0.\} is up to date%
      updated libbar/1.2.0
      EOE

    $pkg_status libfoo >'!libfoo configured 1.0.0';
    $pkg_status libbar >'!libbar configured 1.2.0';

    $pkg_disfigure libbar 2>'disfigured libbar/1.2.0';
    $pkg_purge     libbar 2>'purged libbar/1.2.0';

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.0.0'
  }

  : local-prerequisite
  :
  : Test that the local package can be built against the local prerequisite
  : package.
  :
  {
    # Prepare libbar and libbaz (libbaz->libbar) local packages using the
    # temporary configuration.
    #
    $clone_root_cfg;
    $pkg_fetch -e $src/t4b/libbar-1.1.0.tar.gz && $pkg_unpack libbar;
    cp -r cfg/libbar-1.1.0 libbar;
    $pkg_fetch -e $src/t4c/libbaz-1.1.0.tar.gz && $pkg_unpack libbaz;
    cp -r cfg/libbaz-1.1.0 libbaz;
    rm -r cfg;

    $clone_root_cfg && $rep_add $rep/t4a && $rep_fetch;

    $* ./libbar/ 2>>~%EOE%;
      %.*
      %.*fetched libfoo/1.1.0%
      unpacked libfoo/1.1.0
      configured libfoo/1.1.0
      using libbar/1.1.0 (external)
      configured libbar/1.1.0
      %info: .+dir\{libbar.\} is up to date%
      updated libbar/1.1.0
      EOE

    $* ./libbaz/ 2>>~%EOE%;
      using libbaz/1.1.0 (external)
      configured libbaz/1.1.0
      %info: .+dir\{libbaz.\} is up to date%
      updated libbaz/1.1.0
      EOE

    $pkg_disfigure libbaz 2>'disfigured libbaz/1.1.0';
    $pkg_purge     libbaz 2>'purged libbaz/1.1.0';

    $pkg_disfigure libbar 2>'disfigured libbar/1.1.0';
    $pkg_purge     libbar 2>'purged libbar/1.1.0';

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
  }
}

: prerequisite
:
{
  +$clone_cfg
  +$rep_add $rep/t2 && $rep_add $rep/t5 && $rep_fetch

  : drop
  :
  : Test --drop-prerequisite option.
  :
  {
    $clone_cfg;

    $* --yes libbar/1.0.0 2>>~%EOE%;
      %.*
      %.*fetched libfoo/1.0.0%
      unpacked libfoo/1.0.0
      configured libfoo/1.0.0
      %.*
      %.*fetched libbar/1.0.0%
      unpacked libbar/1.0.0
      configured libbar/1.0.0
      %info: .+dir.+ is up to date%
      updated libbar/1.0.0
      EOE

    $* --drop-prerequisite libbar/1.2.0 <'y' 2>>~%EOE%;
        upgrade libbar/1.2.0
      continue? [Y/n] disfigured libbar/1.0.0
      %.*
      %.*fetched libbar/1.2.0%
      unpacked libbar/1.2.0
      configured libbar/1.2.0
      disfigured libfoo
      purged libfoo
      %info: .+ is up to date%
      updated libbar/1.2.0
      EOE

    $pkg_status libfoo >'libfoo available 1.0.0';

    $pkg_disfigure libbar 2>'disfigured libbar/1.2.0';
    $pkg_purge     libbar 2>'purged libbar/1.2.0'
  }

  : keep
  :
  : Test --keep-prerequisite option.
  :
  {
    $clone_cfg;

    $* --yes libbar/1.0.0 2>>~%EOE%;
      %.*
      %.*fetched libfoo/1.0.0%
      unpacked libfoo/1.0.0
      configured libfoo/1.0.0
      %.*
      %.*fetched libbar/1.0.0%
      unpacked libbar/1.0.0
      configured libbar/1.0.0
      %info: .+dir.+ is up to date%
      updated libbar/1.0.0
      EOE

    $* --keep-prerequisite libbar/1.2.0 <'y' 2>>~%EOE%;
        upgrade libbar/1.2.0
      continue? [Y/n] disfigured libbar/1.0.0
      %.*
      %.*fetched libbar/1.2.0%
      unpacked libbar/1.2.0
      configured libbar/1.2.0
      %info: .+ is up to date%
      updated libbar/1.2.0
      EOE

    $pkg_status libfoo >'libfoo configured 1.0.0';

    $pkg_disfigure libbar 2>'disfigured libbar/1.2.0';
    $pkg_purge     libbar 2>'purged libbar/1.2.0';

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.0.0'
  }
}

: dependent
:
{
  +$clone_cfg
  +$rep_add $rep/t2 && $rep_fetch

  : update
  :
  : Test --update-dependent option.
  :
  {
    $clone_cfg;

    $* --yes libbar 2>>~%EOE%;
      %.*
      %.*fetched libfoo/1.0.0%
      unpacked libfoo/1.0.0
      configured libfoo/1.0.0
      %.*
      %.*fetched libbar/1.0.0%
      unpacked libbar/1.0.0
      configured libbar/1.0.0
      %info: .+ is up to date%
      updated libbar/1.0.0
      EOE

    $rep_add $rep/t4a && $rep_fetch;

    $* --update-dependent libfoo/1.1.0 <'y' 2>>~%EOE%;
        upgrade libfoo/1.1.0
        reconfigure libbar (dependent of libfoo)
      continue? [Y/n] disfigured libbar/1.0.0
      disfigured libfoo/1.0.0
      %.*
      %.*fetched libfoo/1.1.0%
      unpacked libfoo/1.1.0
      configured libfoo/1.1.0
      configured libbar/1.0.0
      %info: .+ is up to date%
      %info: .+ is up to date%
      updated libfoo/1.1.0
      updated libbar/1.0.0
      EOE

    $pkg_disfigure libbar 2>'disfigured libbar/1.0.0';
    $pkg_purge     libbar 2>'purged libbar/1.0.0';

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
  }

  : leave
  :
  : Test --leave-dependent option.
  :
  {
    $clone_cfg;

    $* --yes libbar 2>>~%EOE%;
      %.*
      %.*fetched libfoo/1.0.0%
      unpacked libfoo/1.0.0
      configured libfoo/1.0.0
      %.*
      %.*fetched libbar/1.0.0%
      unpacked libbar/1.0.0
      configured libbar/1.0.0
      %info: .+ is up to date%
      updated libbar/1.0.0
      EOE

    $rep_add $rep/t4a && $rep_fetch;

    $* --leave-dependent libfoo/1.1.0 <'y' 2>>~%EOE%;
        upgrade libfoo/1.1.0
        reconfigure libbar (dependent of libfoo)
      continue? [Y/n] disfigured libbar/1.0.0
      disfigured libfoo/1.0.0
      %.*
      %.*fetched libfoo/1.1.0%
      unpacked libfoo/1.1.0
      configured libfoo/1.1.0
      configured libbar/1.0.0
      %info: .+ is up to date%
      updated libfoo/1.1.0
      EOE

    $pkg_disfigure libbar 2>'disfigured libbar/1.0.0';
    $pkg_purge     libbar 2>'purged libbar/1.0.0';

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
  }
}

: configure-only
:
: Test --configure-only option.
:
{
  $clone_cfg;
  $rep_add $rep/t2 && $rep_fetch;

  $* --configure-only --yes libbar 2>>~%EOE%;
    %.*
    %.*fetched libfoo/1.0.0%
    unpacked libfoo/1.0.0
    configured libfoo/1.0.0
    %.*
    %.*fetched libbar/1.0.0%
    unpacked libbar/1.0.0
    configured libbar/1.0.0
    EOE

  $pkg_disfigure libbar 2>'disfigured libbar/1.0.0';
  $pkg_purge     libbar 2>'purged libbar/1.0.0';

  $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';
  $pkg_purge     libfoo 2>'purged libfoo/1.0.0'
}

: repository-location
:
{
  test.arguments += --yes --auth all --trust-yes

  : all-packages
  :
  {
    : explicit
    :
    {
      $clone_root_cfg;

      $* "@$rep/t4d" 2>>~%EOE%;
        %.+
        %info: .+libfox-1.0.0.+ is up to date%
        %info: .+libbiz-1.0.0.+ is up to date%
        updated libfox/1.0.0
        updated libbiz/1.0.0
        EOE

      $pkg_disfigure libbiz 2>'disfigured libbiz/1.0.0';
      $pkg_purge     libbiz 2>'purged libbiz/1.0.0';

      $pkg_disfigure libfox 2>'disfigured libfox/1.0.0';
      $pkg_purge     libfox 2>'purged libfox/1.0.0';

      $pkg_disfigure libbaz 2>'disfigured libbaz/1.1.0';
      $pkg_purge     libbaz 2>'purged libbaz/1.1.0';

      $pkg_disfigure libbar 2>'disfigured libbar/1.1.0';
      $pkg_purge     libbar 2>'purged libbar/1.1.0';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
    }

    : url-detection
    :
    {
      $clone_root_cfg;

      if ($remote != true)
        rep = ($cxx.target.class != 'windows' \
               ? "file:$rep" \
               : "file:/$regex.replace($rep, '\\', '/')")
      end;

      $* "$rep/t4d" 2>>~%EOE%;
        %.+
        %info: .+libfox-1.0.0.+ is up to date%
        %info: .+libbiz-1.0.0.+ is up to date%
        updated libfox/1.0.0
        updated libbiz/1.0.0
        EOE

      $pkg_disfigure libbiz 2>'disfigured libbiz/1.0.0';
      $pkg_purge     libbiz 2>'purged libbiz/1.0.0';

      $pkg_disfigure libfox 2>'disfigured libfox/1.0.0';
      $pkg_purge     libfox 2>'purged libfox/1.0.0';

      $pkg_disfigure libbaz 2>'disfigured libbaz/1.1.0';
      $pkg_purge     libbaz 2>'purged libbaz/1.1.0';

      $pkg_disfigure libbar 2>'disfigured libbar/1.1.0';
      $pkg_purge     libbar 2>'purged libbar/1.1.0';

      $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
      $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
    }
  }

  : multiple-packages
  :
  {
    $clone_root_cfg;

    $* "libfox,libbiz/1.0.0@$rep/t4d" 2>>~%EOE%;
      %.+
      %info: .+libfox-1.0.0.+ is up to date%
      %info: .+libbiz-1.0.0.+ is up to date%
      updated libfox/1.0.0
      updated libbiz/1.0.0
      EOE

    $pkg_disfigure libbiz 2>'disfigured libbiz/1.0.0';
    $pkg_purge     libbiz 2>'purged libbiz/1.0.0';

    $pkg_disfigure libfox 2>'disfigured libfox/1.0.0';
    $pkg_purge     libfox 2>'purged libfox/1.0.0';

    $pkg_disfigure libbaz 2>'disfigured libbaz/1.1.0';
    $pkg_purge     libbaz 2>'purged libbaz/1.1.0';

    $pkg_disfigure libbar 2>'disfigured libbar/1.1.0';
    $pkg_purge     libbar 2>'purged libbar/1.1.0';

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
  }

  : package-in-complement
  :
  {
    $clone_root_cfg;

    $* "libfoo@$rep/t4d" 2>>~%EOE%;
      %.+
      %info: .+libfoo-1.0.0.+ is up to date%
      updated libfoo/1.0.0
      EOE

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.0.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.0.0'
  }

  : system
  :
  {
    $clone_root_cfg;

    $* "sys:libbiz/2.0.0@$rep/t4d" 2>>~%EOE%;
      %.+
      configured sys:libbiz/2.0.0
      EOE

    $pkg_disfigure libbiz 2>'purged libbiz/2.0.0'
  }

  : non-existent-package
  :
  {
    $clone_root_cfg;

    $* "libbar@$rep/t4d" 2>>~%EOE% != 0
      %.+
      error: package libbar is not found in pkg:build2.org/pkg-build/t4d or its complements
      EOE
  }

  : location-search
  :
  : Test that the repository location is searched in the database before being
  : parsed. The latest would fail as the repository type would be misguessed.
  :
  {
    $clone_root_cfg;
    $rep_add $src/libfoo-1.1.0 --type dir && $rep_fetch;

    d = $canonicalize([dir_path] $src/libfoo-1.1.0);

    $* "libfoo@$d" 2>>~"%EOE%";
      fetching dir:$d
      using libfoo/1.1.0 \(external\)
      configured libfoo/1.1.0
      %info: .+dir\\{libfoo.\\} is up to date%
      updated libfoo/1.1.0
      EOE

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
  }
}

: dir-rep
:
{
  : preferred
  :
  : Test that dir (local) repository is preferred over non-dir local repository
  : that comes first.
  :
  {
    $clone_root_cfg;
    $rep_fetch $rep/t4a;
    $rep_add $src/libfoo-1.1.0 --type dir;
    $rep_fetch "dir:$canonicalize([dir_path] $src/libfoo-1.1.0)";

    $* libfoo 2>>~%EOE%;
      using libfoo/1.1.0 (external)
      configured libfoo/1.1.0
      %info: .+dir\{libfoo.\} is up to date%
      updated libfoo/1.1.0
      EOE

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0';
    $pkg_purge     libfoo 2>'purged libfoo/1.1.0'
  }
}

: keep-out
:
{
  +$cfg_create cxx "config.cxx=$config.cxx" -d cfg 2>- &cfg/***

  # Build libhello as an external package.
  #
  +cp -r $src/libhello-1.0.0 ./libhello
  +$rep_add libhello --type dir
  +$rep_fetch
  +$* libhello 2>!

  # Move libhello version ahead.
  #
  +sed -i -e 's/(version: 1.0).0/\1.1/' libhello/manifest
  +$rep_fetch

  test.arguments += --yes # Is a command-specific option.

  : unspecified
  :
  : Test that libhello is fully rebuilt.
  :
  {
    $clone_cfg;
    $rep_fetch;

    $* libhello 2>>~%EOE%
      disfigured libhello/1.0.0
      using libhello/1.0.1 (external)
      configured libhello/1.0.1
      %mkdir .+%+
      %c\+\+ .+%+
      %ld .+%+
      updated libhello/1.0.1
      EOE
  }

  : specified
  :
  {
    test.arguments += --keep-out

    +$clone_cfg

    : dir-repo
    :
    : Test that libhello is built incrementally. May re-link due to the
    : configuration copying.
    :
    {
      $clone_cfg;

      $* libhello 2>>~%EOE%;
        disfigured libhello/1.0.0
        using libhello/1.0.1 (external)
        configured libhello/1.0.1
        %ld .+%*
        updated libhello/1.0.1
        EOE

      test -d cfg/libhello/;
      test -d cfg/libhello-1.0.1/ == 1
    }

    : directory
    :
    : Test that libhello is built incrementally. May re-link due to the
    : configuration copying.
    :
    {
      +$clone_cfg

      # To avoid 'external package is already available' failure for the
      # nested tests.
      #
      +$rep_remove --all

      : arg
      :
      {
        $clone_cfg;

        $* ../../../libhello/ 2>>~%EOE%;
          disfigured libhello/1.0.0
          using libhello/1.0.1 (external)
          configured libhello/1.0.1
          %ld .+%*
          updated libhello/1.0.1
          EOE

        test -d cfg/libhello/;
        test -d cfg/libhello-1.0.1/ == 1
      }

      : unpacked
      :
      {
        $clone_cfg;
        $pkg_disfigure libhello --keep-out 2>!;
        $pkg_unpack -r -e ../../../libhello;

        $* libhello 2>>~%EOE%;
          configured libhello/1.0.1
          %ld .+%*
          updated libhello/1.0.1
          EOE

        test -d cfg/libhello/;
        test -d cfg/libhello-1.0.1/ == 1
      }
    }

    : archive
    :
    : Test that libhello is fully rebuilt, as the resulted package is not
    : external.
    {
      clone_cfg = cp -p --no-cleanup -r ../../cfg ./

      +$build 'dist(../../libhello/@./out/)' \
              "config.cxx=$config.cxx" config.dist.root=./ \
              config.dist.archives=tar.gz 2>! \
              &out/*** &libhello-1.0.1/*** &libhello-1.0.1.tar.gz

      : arg
      :
      {
        $clone_cfg;

        $* ../libhello-1.0.1.tar.gz 2>>~%EOE%;
          disfigured libhello/1.0.0
          fetched libhello/1.0.1
          unpacked libhello/1.0.1
          configured libhello/1.0.1
          %c\+\+ .+%+
          %ld .+%+
          updated libhello/1.0.1
          EOE

        test -d cfg/libhello-1.0.1/;
        test -d cfg/libhello/ == 1;

        $pkg_disfigure libhello 2>'disfigured libhello/1.0.1';
        $pkg_purge     libhello 2>'purged libhello/1.0.1';

	rm -r cfg/
      }

      : unpacked
      :
      {
        $clone_cfg;

        $pkg_disfigure libhello 2>!;
        $pkg_fetch -r -e ../libhello-1.0.1.tar.gz;
        $pkg_unpack libhello;

        $* libhello 2>>~%EOE%;
          configured libhello/1.0.1
          %c\+\+ .+%+
          %ld .+%+
          updated libhello/1.0.1
          EOE

        test -d cfg/libhello-1.0.1/;
        test -d cfg/libhello/ == 1;

        $pkg_disfigure libhello 2>'disfigured libhello/1.0.1';
        $pkg_purge     libhello 2>'purged libhello/1.0.1';

	rm -r cfg/
      }
    }
  }

  -$pkg_disfigure libhello 2>'disfigured libhello/1.0.0'
  -$pkg_purge     libhello 2>'purged libhello/1.0.0'
}

# @@ Uncomment when support for dependency up/down-grade is added.
#\
: dependency
:
{
  test.arguments += --yes

  +$clone_cfg
  +$rep_add $rep/t4d $rep/t5 && $rep_fetch

  : unknown
  :
  {
    +$clone_cfg

    : name
    :
    {
      $clone_cfg;

      $* ?libbox 2>'error: unknown package libbox' != 0
    }

    : version
    :
    {
      $clone_cfg;

      $* ?libbar/3 2>>EOE != 0
      error: libbar/3 is not available in source
        info: specify sys:libbar/3 if it is available from the system
      EOE
    }
  }

  : available
  :
  {
    +$clone_cfg

    : no-dependent
    :
    {
      $clone_cfg;

      $* ?libbar;
      $* ?libbar/1.2.0; # Buildable.
      $* ?libbar/1.1.0  # Unbuildable.
    }

    : dependent
    :
    {
      +$clone_cfg

      : no-version
      :
      {
        $clone_cfg;

        $* ?libbar libbiz 2>>~%EOE%;
          %.+
          updated libbar/1.2.0
          updated libbiz/1.0.0
          EOE

        $pkg_status libbar >'libbar configured 1.2.0';

        $pkg_drop libbiz
      }

      : version
      :
      {
        $clone_cfg;

        $* ?libbar/1.1.0 libbiz 2>>~%EOE%;
          %.+
          configured libfoo/1.1.0
          %.+
          updated libbar/1.1.0
          updated libbiz/1.0.0
          EOE

        $pkg_status libbar >'libbar configured !1.1.0 available 1.2.0';

        $pkg_drop libbiz
      }
    }
  }
}
#\

: iter
:
{
  test.arguments += --yes # Is a command-specific option.

  : already-available
  :
  {
    $clone_root_cfg;
    $rep_add $src/libfoo-1.1.0 --type dir && $rep_fetch;

    $* $src/libfoo-1.1.0/ 2>>~%EOE% != 0
      %error: external package libfoo/1.1.0 is already available from dir:.+libfoo-1.1.0%
      EOE
  }

  : upgrade
  :
  {
    $clone_root_cfg;

    $* $src/libfoo-1.1.0/ 2>>~%EOE%;
      using libfoo/1.1.0 (external)
      configured libfoo/1.1.0
      %info: .+dir\{libfoo.\} is up to date%
      updated libfoo/1.1.0
      EOE

    cp -p -r $src/libfoo-1.1.0 libfoo;

    $* libfoo/ 2>>~%EOE%;
      disfigured libfoo/1.1.0
      using libfoo/1.1.0#1 (external)
      configured libfoo/1.1.0#1
      %info: .+dir\{libfoo.\} is up to date%
      updated libfoo/1.1.0#1
      EOE

    $rep_add $src/libfoo-1.1.0 --type dir && $rep_fetch;

    $* libfoo 2>>~%EOE%;
      disfigured libfoo/1.1.0#1
      using libfoo/1.1.0#2 (external)
      configured libfoo/1.1.0#2
      %info: .+dir\{libfoo.\} is up to date%
      updated libfoo/1.1.0#2
      EOE

    $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0#2'
  }
}

: git-rep
:
if ($git_supported != true)
{
  # Skip git repository tests.
  #
}
else
{
  rep0 = "$rep_git/state0"
  rep1 = "$rep_git/state1"

  test.arguments += --yes

  pkg_disfigure += 2>!
  pkg_purge     += 2>!

  : prerequisite-repo
  :
  : Prerequisite package of the dependent being built is in the prerequisite
  : repository.
  :
  {
    $clone_root_cfg;
    $rep_add "$rep0/libbar.git#master";
    $rep_add "$rep0/style-basic.git#master";
    $rep_fetch &cfg/.bpkg/repos/*/***;

    $* libmbar 2>>~%EOE%;
      %dist style-basic-.+%
      %checked out style-basic/.+%
      %configured style-basic/.+%
      dist libmbar-1.0.0
      checked out libmbar/1.0.0
      configured libmbar/1.0.0
      %info: .+dir\{libmbar-.+\} is up to date%
      updated libmbar/1.0.0
      EOE

    $pkg_disfigure libmbar;
    $pkg_disfigure style-basic;

    $pkg_purge libmbar;
    $pkg_purge style-basic
  }

  : no-prerequisite-repos
  :
  : Dependent package repository has no prerequisites nor complements. Its
  : dependency is picked up via the root repository that complements its
  : repository (see rep_fetch() function implementation for details).
  :
  {
    $clone_root_cfg;
    $rep_add "$rep1/libbaz.git#master";
    $rep_add "$rep0/style-basic.git#master";
    $rep_fetch &cfg/.bpkg/repos/*/***;

    $* libbaz 2>>~%EOE%;
      %dist style-basic-.+%
      %checked out style-basic/.+%
      %configured style-basic/.+%
      dist libbaz-1.0.0
      checked out libbaz/1.0.0
      configured libbaz/1.0.0
      %info: .+dir\{libbaz-.+\} is up to date%
      updated libbaz/1.0.0
      EOE

    $pkg_disfigure libbaz;
    $pkg_disfigure style-basic;

    $pkg_purge libbaz;
    $pkg_purge style-basic
  }

  : build-unpacked
  :
  : Test that the unpacked external package is properly built for the first
  : time and is not rebuilt afterwards via the directory argument.
  :
  if ($remote != true)
  {
    $clone_root_cfg;

    d = $canonicalize([dir_path] $out_git/state0/style-basic.git);
    $pkg_unpack -e $d;

    $* style-basic 2>>~%EOE%;
      %configured style-basic/1\.1\.0-a\.0\.\d+\..+%
      %info: .+style-basic.+ is up to date%
      %updated style-basic/1\.1\.0-a\.0\.\d+\..+%
      EOE

    $* $d 2>>~%EOE%;
      %info: .+style-basic.+ is up to date%
      %updated style-basic/1\.1\.0-a\.0\.\d+\..+%
      EOE

    $pkg_disfigure style-basic
  }
}