# file      : tests/sync.testscript
# license   : MIT; see accompanying LICENSE file

.include common.testscript

config_cxx = [cmdline] cc config.cxx=$quote($recall($cxx.path) $cxx.config.mode, true)

new    += 2>!
init   += 2>!
config += 2>!
status += --all --recursive -d prj
deinit += -d prj

: single-pkg-cfg
:
{
  $new -C @cfg prj $config_cxx &prj/*** &prj-cfg/***;

  $new -t lib libprj &libprj/***;

  cat <<EOI >+prj/repositories.manifest;
    :
    role: prerequisite
    location: ../libprj
    type: dir
    EOI

  cat <<EOI >+prj/manifest;
    depends: libprj
    EOI

  sed -i -e 's/^(#import .+)$/import libs += libprj%lib{prj}/' \
      prj/prj/buildfile;

  cat <<EOI >=prj/prj/prj.cxx;
    #include <iostream>

    #include <libprj/prj.hxx>

    using namespace std;

    int main (int argc, char* argv[])
    {
      if (argc < 2)
      {
        cerr << "error: missing name" << endl;
        return 1;
      }

      prj::say_hello (cout, argv[1]);
    }
    EOI

  $* -d prj 2>>/~%EOE%;
    %fetching dir:.+/libprj \(prerequisite of dir:.+/prj\)%
    synchronizing:
    %  new libprj.+ \(required by prj\)%
    %  upgrade prj.+19700101000000#1%
    EOE

  $status >>~%EOO%;
    prj configured 0.1.0-a.0.19700101000000#1
    %  libprj configured 0.+%
    EOO

  $build prj/ 2>>~%EOE%;
    %(mkdir|version|c\+\+|ld|ln) .+%{8}
    EOE

  $build 'clean:' prj/ 2>>~%EOE%;
    %(rm|rmdir) .+%{3}
    EOE

  $deinit 2>>/"EOE"
    deinitializing in project $~/prj/
    synchronizing:
      drop prj
      drop libprj
    EOE
}

: multi-pkg-cfg
:
{
  $new -t empty prj &prj/***;

  $new --package pkg1 -d prj;
  $new --package pkg2 -d prj;

  init += -d prj;

  $init -C @cfg1 $config_cxx &prj-cfg1/***;
  $init -C @cfg2 $config_cxx &prj-cfg2/***;

  $new -t lib libprj &libprj/***;

  cat <<EOI >+prj/repositories.manifest;
    :
    role: prerequisite
    location: ../libprj
    type: dir
    EOI

  cat <<EOI >+prj/pkg1/manifest;
    depends: libprj
    EOI

  sed -i -e 's/^(#import .+)$/import libs += libprj%lib{prj}/' \
      prj/pkg1/pkg1/buildfile;

  cat <<EOI >=prj/pkg1/pkg1/pkg1.cxx;
    #include <iostream>

    #include <libprj/prj.hxx>

    using namespace std;

    int main (int argc, char* argv[])
    {
      if (argc < 2)
      {
        cerr << "error: missing name" << endl;
        return 1;
      }

      prj::say_hello (cout, argv[1]);
    }
    EOI

  cat <<EOI >+prj/pkg2/manifest;
    tags: c++
    EOI

  # Sync the default (cfg1) configuration (via the package directory).
  #
  $* -d prj/pkg2 2>>/~%EOE%;
    %fetching dir:.+/libprj \(prerequisite of dir:.+/prj\)%
    synchronizing:
    %  new libprj.+ \(required by pkg1\)%
    %  upgrade pkg1.+19700101000000#1%
    %  upgrade pkg2.+19700101000000#1%
    EOE

  $status >>~%EOO% 2>>/~%EOE%; # Note: implicitly fetches into cfg2.
    in configuration @cfg1:
    pkg1 configured 0.1.0-a.0.19700101000000#1
    %  libprj configured 0.+%
    pkg2 configured 0.1.0-a.0.19700101000000#1

    in configuration @cfg2:
    pkg1 configured 0.1.0-a.0.19700101000000 available 0.1.0-a.0.19700101000000#1
    pkg2 configured 0.1.0-a.0.19700101000000 available 0.1.0-a.0.19700101000000#1
    EOO
    %fetching dir:.+/libprj \(prerequisite of dir:.+/prj\)%
    EOE

  # Sync all configurations (via the project directory).
  #
  $* --all -d prj 2>>~%EOE%;
    in configuration @cfg1:

    in configuration @cfg2:
    synchronizing:
    %  new libprj.+ \(required by pkg1\)%
      upgrade pkg1/0.1.0-a.0.19700101000000#1
      upgrade pkg2/0.1.0-a.0.19700101000000#1
    EOE

  $status >>~%EOE%;
    in configuration @cfg1:
    pkg1 configured 0.1.0-a.0.19700101000000#1
    %  libprj configured 0.+%
    pkg2 configured 0.1.0-a.0.19700101000000#1

    in configuration @cfg2:
    pkg1 configured 0.1.0-a.0.19700101000000#1
    %  libprj configured 0.+%
    pkg2 configured 0.1.0-a.0.19700101000000#1
    EOE

  $build prj/pkg1/ 2>>~%EOE%;
    %(mkdir|version|c\+\+|ld|ln) .+%{8}
    EOE

  $build prj/pkg2/ 2>>~%EOE%;
    %(mkdir|c\+\+|ld|ln) .+%{4}
    EOE

  $build 'clean:' prj/pkg1/ 2>>~%EOE%;
    %(rm|rmdir) .+%{3}
    EOE

  $build 'clean:' prj/pkg2/ 2>>~%EOE%;
    %(rm|rmdir) .+%{3}
    EOE

  $deinit 2>>/"EOE"
    deinitializing in project $~/prj/
    deinitializing package pkg1
    deinitializing package pkg2
    synchronizing:
      drop pkg1
      drop libprj
      drop pkg2
    EOE
}

: config-vars
:
{
  $new prj &prj/***;

  cat <<EOI >+prj/build/root.build;
    config [bool] config.prj.develop ?= false
    config [bool] config.prj.extra ?= true

    text "develop=$config.prj.develop"
    text "extra=$config.prj.extra"
    EOI

  $init -d prj -C @cfg $config_cxx &prj-cfg/*** 2>>~/EOE/;
    /.*/+
    /.*: develop=true/
    /.*: extra=true/
    EOE

  # Reconfigure.
  #
  $* -d prj config.prj.develop=false config.prj.extra=false 2>>~/EOE/;
    /.*/+
    /.*: develop=false/
    /.*: extra=false/
    EOE

  # Make sure the configuration is by default preserved on reconfiguration.
  #
  cat <<EOI >+prj/manifest;
    tags: c++
    EOI

  $* -d prj config.prj.develop=false config.prj.extra=false 2>>~/EOE/;
    /.*/+
    /.*: develop=false/
    /.*: extra=false/
    EOE

  # Make sure --disfigure causes a from-scratch reconfiguration.
  #
  $* -d prj --disfigure config.prj.extra=false 2>>~/EOE/;
    /.*/+
    /.*: develop=true/
    /.*: extra=false/
    EOE

  # Make sure --disfigure alone triggers reconfiguration.
  #
  $* -d prj --disfigure 2>>~/EOE/
    /.*/+
    /.*: develop=true/
    /.*: extra=true/
    EOE
}

: dependency-config
:
{
  +$new -t lib libfoo &libfoo/***
  +$new -t lib libfix &libfix/***
  +$new        bar    &bar/***

  +cat <<EOI >+libfoo/repositories.manifest
    :
    role: prerequisite
    location: ../bar
    type: dir
    EOI

  +cat <<EOI >+libfoo/manifest
    depends: * bar
    EOI

  +cat <<EOI >+libfoo/buildfile
    import bar = bar%exe{bar}
    EOI

  +cat <<EOI >+libfix/repositories.manifest
    :
    role: prerequisite
    location: ../bar
    type: dir
    EOI

  +cat <<EOI >+libfix/manifest
    depends: * bar
    EOI

  +cat <<EOI >+libfix/buildfile
    import bar = bar%exe{bar}
    EOI

  +cat <<EOI >=bar/build/export.build
    export $out_root/$import.target
    EOI

  : create
  {
    cp -rp ../libfoo ./;
    cp -rp ../libfix ./;
    cp -rp ../bar    ./;

    $init -d libfoo -C            @cfg --no-sync $config_cxx &libfoo-cfg/***;
    $init -d libfix -A libfoo-cfg @cfg --no-sync;

    $* -d libfoo 2>>~%EOE% != 0;
      %fetching dir:.+bar \(prerequisite of dir:.+libfoo\)%
      error: unable to find configuration of host type for build-time dependency
        info: run sync command explicitly
      %info: while searching for configuration for build-time dependency bar of package libfoo/.+ \[.+libfoo-cfg.\]%
      %info: while synchronizing configuration .+libfoo-cfg.%
      EOE

    $* -d libfoo --create-host-config &libfoo-host/*** &libf??/**/bootstrap/*** 2>>~%EOE%
      synchronizing:
      %  new bar/.+ \[.+libfoo-host.\] \(required by libfix, libfoo\)%
      %  new libfoo/.+%
      %  new libfix/.+%
      EOE
  }

  : find
  :
  {
    cp -rp ../libfoo ./;
    cp -rp ../libfix ./;
    cp -rp ../bar    ./;

    $config create -d libfoo                    @cfg  libfoo-cfg -- &libfoo-cfg/***;
    $config create -d libfoo --config-type host @host host       -- &host/***;

    $config link -d libfoo @cfg @host;

    # Convert specific warnings to infos as we expect them to appear. This, in
    # particular, prevents bbot workers to set task result status to warning.
    #
    $init -d libfix -A libfoo-cfg @cfg --no-sync 2>&1 | \
    sed -e 's/warning: (added configuration @cfg already linked .*)/info: \1/' >&2 2>!;

    # While at it, test synchronizing via the init command.
    #
    $init -d libfoo @cfg &libf??/**/bootstrap/*** 2>>~%EOE%
      %initializing in project .+libfoo.%
      %fetching dir:.+bar \(prerequisite of dir:.+libfoo\)%
      synchronizing:
      %  new bar/.+ \[.+host.\] \(required by libfix, libfoo\)%
      %  new libfoo/.+%
      %  new libfix/.+%
      EOE
  }

  : re-associate
  :
  : Test that while failing, bdep-init re-associates the automatically created
  : build-time dependency configurations.
  :
  {
    cp -rp ../libfoo ./;
    cp -rp ../libfix ./;
    cp -rp ../bar    ./;

    cat <<EOI >+bar/manifest;
      depends: * libbuild2-baz
      EOI

    $config create -d libfoo @cfg libfoo-cfg -- &libfoo-cfg/***;

    # Convert specific errors to infos as we expect them to appear. Not doing
    # so, makes bbot logs quite confusing.
    #
    $init -d libfoo --create-host-config --create-build2-config @cfg &libfoo-host/*** &libfoo-build2/*** 2>&1 != 0 | \
    sed -e 's/error: (unknown dependency libbuild2-baz .*)/info: \1/' >&2 2>!;

    $config list -d libfoo >>~%EOO%
      %(@cfg|@host|@build2).+%{3}
      EOO
  }
}
